How to Detect LinkedIn Ads on Any Website (API Guide)

July 15, 2026 · 9 min read

A company running LinkedIn Ads is telling you something specific: it sells to businesses, it has a paid acquisition budget, and someone inside it is accountable for pipeline. LinkedIn is the most expensive mainstream ad platform per click, so nobody runs it casually. That makes the LinkedIn Ads footprint one of the cleanest B2B technographic signals there is, and unlike ad spend itself, the footprint is publicly visible in the website's own HTML.

This guide covers what LinkedIn Ads leaves behind on a page, how to spot it by hand in DevTools, why manual checks stop working the moment you have a list instead of a domain, and how to automate detection with the DetectZeStack API. The worked example is a real scan of a real site.

What LinkedIn Ads Leaves Behind on a Website

To measure conversions and build retargeting audiences, LinkedIn requires advertisers to instrument their own website. That instrumentation is the detectable artifact. It comes in two connected pieces.

The LinkedIn Insight Tag and _linkedin_partner_id

The Insight Tag is the snippet LinkedIn's campaign manager asks every advertiser to paste into their site. It looks like this:

<script type="text/javascript">
  _linkedin_partner_id = "1234567";
  window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];
  window._linkedin_data_partner_ids.push(_linkedin_partner_id);
</script>
<script type="text/javascript">
  (function(l) { /* loads snap.licdn.com/li.lms-analytics/insight.min.js */ })();
</script>
<noscript>
  <img height="1" width="1" style="display:none;" alt=""
    src="https://px.ads.linkedin.com/collect/?pid=1234567&fmt=gif" />
</noscript>

Three parts of that snippet are fingerprints. The _linkedin_partner_id variable is the advertiser's public account identifier and appears nowhere else on the web. The loader pulls insight.min.js from snap.licdn.com, LinkedIn's static asset host. And the noscript fallback embeds a one-pixel image served from px.ads.linkedin.com, so the conversion still registers for visitors with JavaScript disabled. Any one of the three is enough to identify a LinkedIn advertiser.

Network Requests to px.ads.linkedin.com and snap.licdn.com

Once the tag runs, the browser makes a predictable set of requests. snap.licdn.com serves the Insight Tag script itself. px.ads.linkedin.com receives the tracking beacons: page views, conversion events, and audience-matching calls, each carrying the partner ID. Older integrations also reference dc.ads.linkedin.com, a legacy pixel host that still appears in the wild. Some security-conscious sites even name px.ads.linkedin.com in their Content-Security-Policy header to allow the beacon through, which turns the response headers themselves into a detection surface.

How to Detect LinkedIn Ads Manually with Browser DevTools

Checking Page Source for the Insight Tag Snippet

Open the site, hit view-source, and search for _linkedin_partner_id. If the snippet was pasted directly into the page template, you will find it, usually near the closing </body> tag alongside the site's other marketing pixels. Searching for licdn or px.ads.linkedin.com catches the loader and the noscript pixel when the variable name has been minified away.

Watching the Network Tab for LinkedIn Tracking Calls

The runtime check is more reliable than view-source. Open DevTools, switch to the Network tab, filter by linkedin, and reload the page. A LinkedIn advertiser produces a request to snap.licdn.com/li.lms-analytics/insight.min.js followed by one or more beacons to px.ads.linkedin.com/collect. The pid parameter on the beacon is the partner ID, and it confirms the tag is live rather than a leftover from a paused campaign's template.

Why Manual Checks Break Down at Scale

Both manual methods work for one domain. Neither works for two hundred. A DevTools session per domain costs a minute or two of human attention, and the result lives in nobody's CRM. The moment the question changes from "does this site run LinkedIn Ads?" to "which of my 500 target accounts run LinkedIn Ads?", you need the check to be a function call.

Tag Managers Hide the Snippet from View-Source

There is a second, sneakier problem. A large share of companies deploy the Insight Tag through Google Tag Manager rather than pasting it into their HTML. A GTM-injected tag only exists after JavaScript executes in a browser, so view-source shows nothing, and a raw HTML search misses a genuine advertiser. The Network tab still catches it, but that drags you back to a browser per domain. Any detection strategy has to be honest about this layer: HTML-level scanning catches directly-installed tags with certainty, and treats GTM-only installs as inconclusive rather than negative. More on that caveat below.

Detect LinkedIn Ads Programmatically with the DetectZeStack API

Before writing any code, confirm the signal by hand. The /demo endpoint needs no API key and no signup:

curl -s "https://detectzestack.com/demo?url=asana.com" \
  | jq '.technologies[] | select(.name | test("Linkedin"))'

Which returns a live detection:

{
  "name": "Linkedin Ads",
  "categories": ["Advertising"],
  "confidence": 100,
  "description": "Linkedin Ads is a paid marketing tool that offers access to Linkedin social networks through various sponsored posts and other methods.",
  "website": "https://business.linkedin.com/marketing-solutions/ads",
  "icon": "Linkedin.svg",
  "source": "http"
}

Note the canonical spelling: Linkedin Ads, lowercase "i". The fingerprint database spells it Linkedin, not LinkedIn, in both Linkedin Ads and Linkedin Insight Tag. A jq filter on the exact string "LinkedIn Ads" matches nothing. Match on "Linkedin Ads", or use the /check endpoint, which compares names case-insensitively and echoes back the canonical form.

Two related entries can appear in a scan, and they answer slightly different questions:

Detected as Category Signal
Linkedin Ads Advertising Pixel references to px.ads.linkedin.com or dc.ads.linkedin.com in the HTML, or px.ads.linkedin.com named in the Content-Security-Policy header
Linkedin Insight Tag Analytics The _linkedin_partner_id variable in an inline script, or a script loaded from snap.licdn.com/li.lms-analytics/insight.min.js

In practice the two travel together, since the standard snippet produces both sets of signals. Filter for either name, or filter on the Advertising and Analytics categories if you want to catch LinkedIn alongside its neighbors in one pass.

Single Domain Check with GET /analyze

The demo endpoint is rate limited and meant for spot checks. For real volume, get a free API key from RapidAPI and use the authenticated endpoints:

curl -s "https://detectzestack.p.rapidapi.com/analyze?url=asana.com" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" | jq '.'

Reading the JSON Response: technologies, confidence, categories

The response carries the whole stack, which is where the qualification value lives:

{
  "url": "https://asana.com",
  "domain": "asana.com",
  "technologies": [
    { "name": "Amazon Web Services", "categories": ["PaaS"],                  "confidence": 100, "source": "http" },
    { "name": "Linkedin Ads",        "categories": ["Advertising"],           "confidence": 100, "source": "http" },
    { "name": "Netlify",             "categories": ["PaaS", "CDN"],           "confidence": 100, "source": "http" },
    { "name": "Next.js",             "categories": ["JavaScript frameworks", "Web frameworks"], "confidence": 100, "source": "http" },
    { "name": "OneTrust",            "categories": ["Cookie compliance"],     "confidence": 100, "source": "http" },
    { "name": "React",               "categories": ["JavaScript frameworks"], "confidence": 100, "source": "http" },
    { "name": "reCAPTCHA",           "categories": ["Security"],              "confidence": 100, "source": "http" }
  ],
  "categories": {
    "Advertising": ["Linkedin Ads"],
    "Cookie compliance": ["OneTrust"],
    "JavaScript frameworks": ["Next.js", "React"],
    "PaaS": ["Netlify", "Amazon Web Services"],
    "Security": ["HSTS", "reCAPTCHA"]
  },
  "meta": { "status_code": 200, "tech_count": 13, "scan_depth": "full" },
  "cached": false,
  "response_ms": 1204
}

Three fields do the work. confidence is 100 for HTML-derived detections, meaning the fingerprint matched exactly rather than being inferred. source is http, meaning the evidence came from the page the server returned, not from DNS or TLS. And the categories object is a map from category name to the technologies found in it, so testing for a LinkedIn advertiser is one key lookup: .categories.Advertising. A site running Linkedin Ads next to OneTrust cookie consent, as here, is a company with both an ad budget and a compliance function, which is two qualification signals from one request.

When you only need a boolean, /check answers directly and accepts any capitalization:

curl -s "https://detectzestack.p.rapidapi.com/check?url=asana.com&tech=LinkedIn%20Ads" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" | jq '.'
{
  "domain": "asana.com",
  "technology": "Linkedin Ads",
  "detected": true,
  "confidence": 100,
  "version": "",
  "categories": ["Advertising"],
  "response_ms": 431,
  "cached": false
}

The response echoes the canonical name Linkedin Ads regardless of how you spelled the query. version is empty because ad pixels do not expose version strings; that is expected, not a weak detection.

Scanning a Prospect List with POST /analyze/batch

Batch is how you work through a list. It accepts up to 10 URLs per request and scans them concurrently:

curl -s -X POST "https://detectzestack.p.rapidapi.com/analyze/batch" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["asana.com", "monday.com", "gong.io"]}' \
  | jq -r '.results[]
      | select(.result.technologies[]?.name | test("Linkedin"))
      | .result.domain'

The wrapper response reports total_ms, successful, and failed counts, and each item carries its own error field so one unreachable domain does not sink the batch. Each URL in a batch counts as one request against your monthly quota, so a 10-URL batch costs 10 requests: batching saves wall-clock time and round trips, not quota. For lists in the hundreds or thousands, the batch scanning guide covers chunking, retries, and CSV export end to end.

Absence is inconclusive, for two reasons. First, check meta.status_code: a site that answered the scan with a 403 or 429 returned no HTML to inspect, so nothing script-based could be seen. Second, remember the tag manager problem: an Insight Tag injected by Google Tag Manager never appears in the served HTML. A scan that shows Google Tag Manager but no LinkedIn entry may still be a LinkedIn advertiser. Treat "detected" as a firm yes and "not detected" as unknown, and your list stays honest.

Use Cases: Who Needs LinkedIn Ads Detection

B2B Sales Teams Qualifying Ad-Spend-Ready Prospects

If you sell anything adjacent to demand generation, such as attribution, intent data, landing page tooling, CRM enrichment, or marketing automation, the Insight Tag is a budget detector. LinkedIn's auction floor prices are high enough that an active advertiser has, at minimum, a four-figure monthly experiment running and a person whose job depends on its performance. That person has problems your product might solve, and the tag proves they exist before you write the first email. Pair the LinkedIn signal with a HubSpot detection and you can even guess which team runs it: LinkedIn Ads plus HubSpot is a classic mid-market B2B marketing stack.

Agencies Auditing Competitor Ad Strategies

For agencies, the same scan answers a pitch-preparation question: which of the prospect's competitors are already investing in LinkedIn? Scanning the competitive set takes one batch request and turns "you should consider LinkedIn" into "four of your six competitors have the Insight Tag installed and you do not." The full stack that comes back with the detection, including the analytics platform, tag manager, and consent tooling, sketches the maturity of each competitor's measurement setup for free.

Monitoring When Companies Add or Drop LinkedIn Ads

The signal is most valuable when it changes. A company that just installed the Insight Tag is starting to spend on B2B acquisition right now, which makes this quarter the right time to sell them the surrounding tooling. A company that removed it may be cutting budget, changing agencies, or consolidating channels, and each of those is an opening for somebody. Because every scan returns the full technology list, monitoring is just re-scanning on a schedule and diffing the results: store each domain's technology names, compare against yesterday's, and alert on the delta. The tech change tracking guide walks through building exactly that pipeline with the API.

Get Your API Key

The free plan includes 100 requests per month with no credit card, which is enough to scan your current top-of-funnel list and see how many LinkedIn advertisers are hiding in it. Paid plans scale to 50,000 requests per month for larger prospecting pipelines: Pro is $9 for 1,000 requests, Ultra is $29 for 10,000, and Mega is $79 for 50,000.

Conclusion

LinkedIn Ads detection reduces to a handful of stable fingerprints: the _linkedin_partner_id variable, the insight.min.js script from snap.licdn.com, and the pixel hosts px.ads.linkedin.com and dc.ads.linkedin.com. You can verify any single domain in DevTools in under a minute. Past a handful of domains, the API does the same inspection server-side and hands you the entire technology stack along with the answer, one request per domain, with honest semantics: a hit is certain, a miss is inconclusive. Start with the keyless /demo call above, then point /analyze/batch at your prospect list.

Related Reading

Start Detecting LinkedIn Advertisers Today

100 free API requests/month. No credit card required. Detect LinkedIn Ads and 3,000+ other technologies.

Get Your Free API Key

Get API updates and tech detection tips

Join the mailing list. No spam, unsubscribe anytime.