Snowflake

How to load LinkedIn Ads data into Snowflake with OWOX Data Marts

To get LinkedIn Ads data into Snowflake, create a connector Data Mart, sign in with LinkedIn, enter the ad account, choose the Ad Analytics endpoint and publish. The analytics table identifies each row by URNs, not names, so the useful report comes from joining it to the Campaigns table. Both queries are in this guide.

SnowflakeIevgen Krasovytskyi7 min read

How to load LinkedIn Ads data into Snowflake with OWOX Data Marts

LinkedIn is usually the most expensive click a B2B team buys, and the one it can say least about. Campaign Manager shows clicks and leads. Whether those leads became pipeline is in the CRM, and the two only meet in a spreadsheet somebody maintains by hand.

Putting LinkedIn Ads data into Snowflake is the first step to joining them properly. This guide sets it up with the LinkedIn Ads connector in OWOX Data Marts, and then deals with the part most guides skip: the analytics table that arrives has no campaign names in it.

What you end up with

What you end up with

Two tables in your own Snowflake account.

  • linkedin_ads_ad_analytics: daily performance. Impressions, clicks, cost and engagement for each creative on each day.
  • linkedin_ads_ad_campaigns: one row per campaign with its name, status, objective and type.

Each is a separate connector Data Mart. The connector reads the LinkedIn API, writes the tables and refreshes them on a schedule. It does not model the data. Joining the two tables into a report is SQL you write, shown below.

Before you start

Before you start

In LinkedIn. A LinkedIn user with access to the ad account in Campaign Manager, and the account’s ID, which Campaign Manager shows next to the account name.

In Snowflake. A storage of type Snowflake connected to your project, as described in the storage guide: account identifier, warehouse, and a key pair or a username with a programmatic access token. The role must be able to create a database, a schema and tables. A small dedicated warehouse with auto-suspend is enough, and Snowflake pricing explained shows what a daily load costs.

The Turning Point

OWOX Data Marts

See your first report built in real time. 15 minutes.

  1. Connect your data warehouse
  2. Pick your metrics
  3. Get a live Google Sheets report

In the time it takes to write a ticket. Then imagine never writing that ticket again.

Book a Demo

We'll use your actual use case

Step 1: create the Data Mart

Step 1: create the Data Mart

Click New Data Mart, enter a title such as “LinkedIn Ads Analytics”, select the Snowflake storage and click Create Data Mart. On the Data Setup tab, set Definition Type to Connector and choose LinkedIn Ads.

Step 2: sign in and enter the account

Step 2: sign in and enter the account

Continue with LinkedIn is the short way: sign in as the user who has access to the ad account and allow access.

Manually means creating your own LinkedIn app. The app has to be verified by an administrator of your company page and approved for the Advertising API, which can take up to a day. From it you take a client ID, a primary client secret and a refresh token generated with the r_ads and r_ads_reporting scopes. The credentials guide has each step. The sign-in button avoids all of it.

Edit Connector form for LinkedIn Ads in OWOX Data Marts on a Snowflake Data Mart, with a Continue with LinkedIn button, a Manually link and a required Account URNs field – one sign-in and the account ID connect the source

Then fill in Account URNs with the ID of the ad account.

Step 3: choose the endpoint and the fields

Step 3: choose the endpoint and the fields

Each Data Mart loads one endpoint. LinkedIn Ads has five.

  • Ad Analytics. Daily performance metrics. The one for reporting.
  • Campaigns. Targeting, format, bid strategy, budget and, most usefully, the campaign name.
  • Campaign Groups. The level above campaigns, with shared objectives and budgets.
  • Creatives. The ads themselves.
  • Ad Accounts. Account settings, currency and status.

Create the Ad Analytics Data Mart first and the Campaigns one right after it. You will want both.

Then select fields. Ad Analytics offers a long list, most of it engagement detail: video views, document completions, lead form opens, job applications.

Connector Fields panel for LinkedIn Ads in OWOX Data Marts with 19 of 104 fields selected for the adAnalytics endpoint, and dateRangeStart, dateRangeEnd and pivotValues locked as keys – a row is identified by its date and its pivot values, not by a campaign name

Take impressions, clicks, costInUsd and the conversion or lead fields you report on. For accounts billed in another currency there is also costInLocalCurrency.

The last screen asks for the database, schema and table. The setup proposes a database named after the source, the schema PUBLIC and a table named after the endpoint.

Step 4: publish and run

Step 4: publish and run

Click Publish & Run Data Mart. Publishing starts the first import. When it finishes, the Data Setup tab shows the source, the Snowflake table and its columns.

Data Setup tab of a LinkedIn Ads connector Data Mart in OWOX Data Marts, showing the LinkedInAds source with the adAnalytics endpoint, the Snowflake database, schema and table it writes to, and the output schema starting with dateRangeStart, dateRangeEnd and pivotValues – the table is in your own account

Step 5: load history and set the schedule

Step 5: load history and set the schedule

History. Click Manual Run and choose Backfill (custom period). One backfill run covers at most 31 days. For a longer history, run consecutive periods, each after the previous one has finished.

Manual Run panel in OWOX Data Marts with Backfill (custom period) selected, start and end date fields and a note that a backfill run can cover at most 31 days – history is loaded one month at a time

Schedule. A Data Mart without a trigger does not run again. On the Triggers tab, add a trigger of type Connector Run: daily, weekly, monthly or at an interval.

Create Scheduled Trigger form in OWOX Data Marts on the LinkedIn Ads Data Mart, with trigger type Connector Run, a daily schedule at 09:00 and a time zone – the load repeats without anyone starting it

Scheduled runs are incremental. Each one loads the current day plus the days set by the Reimport Lookback Window, two by default. LinkedIn conversions can be attributed days after the click, so raise the lookback if your reports depend on them. Rows are merged on the keys, so a re-imported day replaces the earlier version.

If a run ends with a warning

LinkedIn’s analytics endpoint returns at most 15,000 rows per request and has no paging. The connector requests one day at a time to stay under that limit. An account with more than 15,000 active creatives on a single day can still exceed it. The run then finishes with a Warning status and lists the affected days, and data for those days may be incomplete.

What the tables look like in Snowflake

What the tables look like in Snowflake

The identifiers are in pivotValues. The connector requests analytics by creative, campaign, campaign group and account at once. LinkedIn returns those four identifiers as URNs, and they arrive together in one text column, in a form like this:

urn:li:sponsoredCreative:…, urn:li:sponsoredCampaign:…,
urn:li:sponsoredCampaignGroup:…, urn:li:sponsoredAccount:…

There is no campaign_name column in this table. You extract the campaign ID from pivotValues and join to the Campaigns table for the name.

Names are case-sensitive, and in camel case. The connector creates the schema, table and column names quoted, exactly as LinkedIn spells them: dateRangeStart, costInUsd. In Snowflake a quoted name is case-sensitive and an unquoted one is read as upper case, so SELECT costInUsd fails. Quote every column, the schema and the table: ads_owox."PUBLIC"."linkedin_ads_ad_analytics". The database name is not quoted.

The day is dateRangeStart. With daily data, dateRangeStart and dateRangeEnd are the same day.

Query the data

Query the data

Both queries were validated on Snowflake against tables loaded by the connector. The examples use a shared database, ads_owox, for all ad platforms.

Cost, clicks and impressions by campaign ID and day:

SELECT
  "dateRangeStart" AS date,
  REGEXP_SUBSTR(
    "pivotValues",
    'sponsoredCampaign:([0-9]+)', 1, 1, 'e'
  ) AS campaign_id,
  SUM("impressions") AS impressions,
  SUM("clicks") AS clicks,
  SUM("costInUsd") AS cost_usd
FROM ads_owox."PUBLIC"."linkedin_ads_ad_analytics"
GROUP BY 1, 2
ORDER BY date, cost_usd DESC;

REGEXP_SUBSTR with the 'e' parameter returns the part in parentheses: the digits after sponsoredCampaign:. Swap in sponsoredCreative or sponsoredCampaignGroup to report at another level.

The same report with campaign names, joined to the Campaigns table:

WITH a AS (
  SELECT
    "dateRangeStart" AS date,
    REGEXP_SUBSTR(
      "pivotValues",
      'sponsoredCampaign:([0-9]+)', 1, 1, 'e'
    ) AS campaign_id,
    "impressions",
    "clicks",
    "costInUsd"
  FROM ads_owox."PUBLIC"."linkedin_ads_ad_analytics"
)
SELECT
  a.date,
  c."name" AS campaign,
  SUM(a."impressions") AS impressions,
  SUM(a."clicks") AS clicks,
  SUM(a."costInUsd") AS cost_usd
FROM a
LEFT JOIN ads_owox."PUBLIC"."linkedin_ads_ad_campaigns" c
  ON a.campaign_id = c."id"
GROUP BY a.date, c."name"
ORDER BY a.date, cost_usd DESC;

This second query is the one worth publishing. Save it as a SQL Data Mart, and the people who read the report see campaign names and never meet a URN.

From table to report

From table to report

On a Data Mart’s Destinations tab you attach reports to Google Sheets, Data Studio, Slack or email, each with its own columns and schedule. Do that on the Data Mart built from the joined query, not on the raw analytics table. Snowflake reports in Google Sheets covers the delivery.

Two directions from here matter for B2B.

LinkedIn next to the other channels. One row per day and channel, with LinkedIn’s costInUsd mapped to the same spend column as the rest. Self-service marketing analytics on Snowflake has that query.

LinkedIn next to pipeline. If CRM data is in Snowflake, the join key is whatever your campaigns write into the lead: a UTM campaign value or the campaign ID. Decide that convention first. The SQL is the easy part.

Where to go next

Where to go next

The same setup loads the other sources into the same Snowflake account: Google Ads, Facebook Ads, Microsoft Ads, TikTok Ads, Reddit Ads and Shopify.

On Databricks the steps are the same and the table names have three parts: see LinkedIn Ads to Databricks. For the layer you build on top, see Snowflake as a reusable reporting layer.

Your New Normal

Turn your data into decisions.

Governed data marts give you the clean foundation ML needs to actually work.

  • No AI hallucinations
  • Analyst-governed definitions
  • Every number traces to SQL
Get started free

FAQ

Frequently Asked Questions

How do I deliver LinkedIn Ads reports from Snowflake to the team?

Publish the query that joins analytics to campaign names as a SQL Data Mart. On its Destinations tab, create reports to Google Sheets, Data Studio, Slack or email, each with its own columns and schedule. Readers get campaign names and current numbers without a Snowflake login.

Why is there no campaign name in the LinkedIn Ads analytics table?

LinkedIn identifies each analytics row by URNs. The connector requests data by creative, campaign, campaign group and account, and the four URNs arrive together in the pivotValues column. Extract the campaign ID with REGEXP_SUBSTR and join to the table loaded from the Campaigns endpoint to get the name. Publishing that joined query as a Data Mart gives readers names directly.

How should I schedule LinkedIn Ads loads?

A daily Connector Run trigger suits most reporting. Each scheduled run is incremental: it loads the current day plus the days set by the Reimport Lookback Window, two by default. Raise the lookback if you report on conversions that LinkedIn attributes several days after the click. Rows are merged on the keys, so re-imported days replace the earlier version.

How can I connect LinkedIn Ads spend to CRM and pipeline data in Snowflake?

Load LinkedIn Ads with the connector and bring CRM data into the same Snowflake account. The join needs a shared key that your campaigns write into the lead record, such as a UTM campaign value or the LinkedIn campaign ID. Agree that convention first, then write the join in SQL and publish it as a Data Mart so the definition is reused.

Which LinkedIn Ads endpoints should I load for reporting?

Ad Analytics for daily performance: impressions, clicks, cost and conversions per creative. Campaigns for the campaign name, status, objective and type. Each endpoint is its own Data Mart and its own table. Campaign Groups, Creatives and Ad Accounts are available when you need those levels or their settings.

Why did my LinkedIn Ads run finish with a warning?

LinkedIn's analytics endpoint returns at most 15,000 rows per request and does not support paging. The connector requests one day at a time to stay under the limit. If a single day still exceeds it, for example in an account with more than 15,000 active creatives, the run ends with a Warning status and lists the affected days, for which data may be incomplete.

How do I load LinkedIn Ads data into Snowflake automatically?

Create a Data Mart in OWOX Data Marts on your Snowflake storage, set its definition type to Connector and choose LinkedIn Ads. Sign in with LinkedIn, enter the ad account ID, pick the Ad Analytics endpoint and the fields you need, then publish. A Connector Run trigger on the Triggers tab repeats the load daily, weekly, monthly or at an interval.

Who wrote this

Ievgen Krasovytskyi

Ievgen Krasovytskyi Head of Marketing

Ievgen Krasovytskyi is the Head of Marketing at OWOX, leading strategy across content, SEO, product marketing, and AI-powered automation. With deep expertise in analytics infrastructure, data warehouses, and marketing technology, he builds systems that connect marketing performance to business outcomes. Ievgen writes about SaaS growth, analytics workflows, and the future of AI in marketing operations.