How to Find Companies Using Klaviyo (API Guide 2026)

July 11, 2026 · 10 min read

Klaviyo is email and SMS marketing for online stores. That single fact makes it one of the most useful signals in ecommerce prospecting: a company running Klaviyo has a product catalog, an email list, a revenue stream worth automating, and a budget line already allocated to retention marketing. They are not evaluating whether ecommerce marketing matters. They have already decided.

This guide shows how Klaviyo is detected from the outside, and how to turn that detection into a prospect list using the DetectZeStack API. Every response shape below comes from the live API, and the worked example is a real store.

Why Companies Using Klaviyo Are a High-Intent Prospect List

Most technographic filters tell you what a company built with. Klaviyo tells you what a company spends on. Klaviyo's pricing scales with the size of the contact list, so a store running it is paying a recurring bill that grows as they grow. That has three consequences for anyone selling into them.

First, it filters out the hobby stores. A storefront with a Klaviyo integration has enough order volume to justify a retention tool, which quietly removes a long tail of abandoned Shopify sites from your list.

Second, it tells you what the company already believes. If you sell reviews software, loyalty programs, SMS tooling, subscription billing, a CDP, or a Shopify app of almost any kind, a Klaviyo store has already accepted the premise that owned-audience marketing is worth paying for. That is the expensive part of the sale, and it is already done.

Third, it composes. Klaviyo rarely appears alone. It sits on top of an ecommerce platform, next to a reviews widget, a subscriptions app, a helpdesk. Detecting Klaviyo gets you the anchor; the rest of the scan gets you the context that makes outreach specific instead of generic.

How Klaviyo Is Detected on a Website

Klaviyo is a client-side integration. To send a browse-abandonment email, Klaviyo has to observe the browsing, which means it has to load JavaScript in the visitor's browser. That requirement is what makes it externally detectable: the store must advertise the integration in its own HTML to every visitor, including a scanner.

The klaviyo.js Script Tag and static.klaviyo.com Assets

The primary signal is the onsite script. A store running Klaviyo serves a script tag pointing at Klaviyo's asset host, typically along these lines:

<script async type="text/javascript"
  src="https://static.klaviyo.com/onsite/js/klaviyo.js?company_id=XXXXXX">
</script>

DetectZeStack matches the script source against Klaviyo's fingerprint, which keys on the klaviyo.com asset domain. Any script served from that domain resolves the site to Klaviyo. This is a strong signal rather than a heuristic one: there is no reason to load a script from Klaviyo's CDN other than to run Klaviyo, so a match returns a confidence of 100.

The company_id in the query string is Klaviyo's public account identifier for that store. It is not a secret, and it is worth noting only because its presence is a good sanity check that you are looking at a live integration rather than a leftover tag.

The _learnq Global and Onsite Tracking Object

Klaviyo's onsite tracking exposes a global queue named _learnq. It is the array a storefront pushes events into, and it is the thing you would look for if you opened a browser console on a Klaviyo store:

// visible in the browser console on a Klaviyo store
_learnq.push(['track', 'Viewed Product', { ProductName: 'Titanium Ridge Wallet' }]);

This is worth understanding, but it is worth being precise about how it relates to detection. _learnq is a JavaScript object that only exists after the page has executed its scripts. DetectZeStack analyzes what the server returns and does not run a headless browser, so it does not evaluate _learnq at runtime. It keys on the script source instead.

In practice this distinction costs you nothing, because the same integration produces both: a store cannot populate _learnq without first loading klaviyo.js. Detecting the script is detecting the integration, and it is dramatically faster than booting a browser per domain. It does mean that if you are debugging a specific store by hand, the console and the API are looking at two different layers of the same thing.

Klaviyo Forms, Signup Embeds, and the Shopify App Footprint

Klaviyo is not one product, and the API distinguishes its parts. Several Klaviyo surfaces carry their own signatures, so a scan can return more than a single Klaviyo entry:

Detected as What it means Signal
Klaviyo Core email and SMS platform with onsite tracking Script served from klaviyo.com
Klaviyo Forms Popup and embedded signup forms for list growth An element carrying the klaviyo-form class
Klaviyo Reviews Product reviews, sold to Shopify and WooCommerce stores Reviews bundle from static.klaviyo.com
Klaviyo Data Platform Klaviyo's CDP and web personalization offering Personalization script from static-tracking.klaviyo.com
Klaviyo Customer Hub Signed-in order tracking and returns experience A k-hub container element

This granularity is a qualification tool, not trivia. A store running only Klaviyo is using the core platform. A store also running Klaviyo Reviews and Klaviyo Customer Hub has consolidated multiple tools onto Klaviyo, which tells you something very different about how hard they will be to displace and which adjacent products they have already stopped shopping for.

Checking a Single Domain for Klaviyo (Free Demo Endpoint)

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=ridge.com" | jq '.'

Filter it down to just the Klaviyo entry to see exactly what a detection looks like:

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

Which returns:

{
  "name": "Klaviyo",
  "categories": [
    "Marketing automation"
  ],
  "confidence": 100,
  "description": "Klaviyo is an email and SMS marketing platform for online businesses.",
  "website": "https://www.klaviyo.com/",
  "icon": "Klaviyo.svg",
  "source": "http"
}

Three fields matter for prospecting. categories places Klaviyo under Marketing automation, which is the value to filter on if you want to catch Klaviyo and its competitors in one pass. confidence is 100, meaning the script source matched rather than a weaker heuristic. source is http, meaning the detection came from the HTML response rather than from a DNS or TLS signal.

API Example: Detect Klaviyo with DetectZeStack

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.

GET /analyze — Full Tech Stack for One Domain

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

The response carries the whole stack, not just the technology you were looking for:

{
  "url": "https://ridge.com",
  "domain": "ridge.com",
  "technologies": [
    { "name": "Klaviyo",       "categories": ["Marketing automation"], "confidence": 100, "source": "http" },
    { "name": "Shopify",       "categories": ["Ecommerce", "CMS"],     "confidence": 100, "source": "http" },
    { "name": "Intelligems",   "categories": ["A/B Testing"],          "confidence": 100, "source": "http" },
    { "name": "Fondue",        "categories": ["Loyalty & rewards"],    "confidence": 100, "source": "http" },
    { "name": "Cloudflare",    "categories": ["CDN"],                  "confidence": 100, "source": "http" },
    { "name": "Let's Encrypt", "categories": ["SSL/TLS certificate authority"], "confidence": 70, "source": "tls" }
  ],
  "categories": {
    "Marketing automation": ["Klaviyo"],
    "Ecommerce": ["Shopify"],
    "A/B Testing": ["Intelligems"],
    "Loyalty & rewards": ["Fondue"],
    "CDN": ["Cloudflare"]
  },
  "meta": { "status_code": 200, "tech_count": 9, "scan_depth": "full" },
  "cached": false,
  "response_ms": 1204
}

Read that stack as a sales brief rather than a list. This store runs Klaviyo for retention, Intelligems for price and offer testing, and Fondue for cashback rewards, all on Shopify. That is a merchant who actively invests in conversion and retention tooling and is willing to run several vendors at once. The categories object is the fastest way to consume this programmatically: it is a map from category name to the technologies found in it, so checking for a Klaviyo store is a single lookup rather than a scan of the array.

The categories map is the filter you want. Filtering on categories["Marketing automation"] catches Klaviyo, Mailchimp, HubSpot, and Braze in one pass. Filtering on the technology name catches Klaviyo specifically. Pick based on whether you are qualifying a category budget or a displacement target.

GET /check?tech=Klaviyo — Yes/No With Confidence Score

When you only need a boolean, /check returns one instead of making you filter the full stack yourself:

curl -s "https://detectzestack.p.rapidapi.com/check?url=ridge.com&tech=Klaviyo" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" | jq '.'
{
  "domain": "ridge.com",
  "technology": "Klaviyo",
  "detected": true,
  "confidence": 100,
  "version": "",
  "categories": ["Marketing automation"],
  "response_ms": 412,
  "cached": false
}

The tech parameter is case insensitive, so tech=klaviyo works and the response echoes back the canonical name Klaviyo. When the technology is absent, detected is false and confidence is 0. Klaviyo does not expose a version string to the outside world, so version is an empty string here; that is expected and not a failed detection.

POST /analyze/batch — Scan a List of Prospect Domains

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": ["ridge.com", "bombas.com", "nomadgoods.com"]}' | jq '.'

The response wraps one result per URL, with a per-item error field so a single bad domain does not fail the batch:

{
  "results": [
    { "url": "ridge.com",      "result": { "domain": "ridge.com", "technologies": [ ... ] } },
    { "url": "bombas.com",     "result": { "domain": "bombas.com", "technologies": [ ... ] } },
    { "url": "nomadgoods.com", "result": { "domain": "nomadgoods.com", "technologies": [ ... ] } }
  ],
  "total_ms": 2310,
  "successful": 3,
  "failed": 0
}

To pull only the Klaviyo users out of a batch, filter on the nested technology list:

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": ["ridge.com", "bombas.com", "nomadgoods.com"]}' \
  | jq -r '.results[]
      | select(.result.technologies[]?.name == "Klaviyo")
      | .result.domain'

Each URL in a batch counts as one request against your monthly quota, so a 10-URL batch costs 10 requests. Batching saves round trips and wall-clock time, not quota.

GET /lookup?tech=Klaviyo — Pull Domains Already Known to Use Klaviyo

The endpoints above answer "does this domain run Klaviyo?" and require you to bring the domains. /lookup inverts the question: it returns domains already in DetectZeStack's scan index that were observed running Klaviyo.

curl -s "https://detectzestack.p.rapidapi.com/lookup?tech=Klaviyo&limit=50" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" | jq '.'
{
  "technology": "Klaviyo",
  "total": 128,
  "results": [
    {
      "domain": "ridge.com",
      "category": "Marketing automation",
      "confidence": 100,
      "version": "",
      "first_seen": "2026-05-02",
      "last_seen": "2026-07-11"
    }
  ],
  "limit": 50,
  "offset": 0,
  "response_ms": 18
}

Two fields here have no equivalent in a live scan. first_seen is when the domain was first observed running Klaviyo, and last_seen is the most recent confirmation. A domain whose first_seen is recent is a store that just adopted Klaviyo, which is a materially better lead than one that has run it for three years: they are actively building out retention, budget is moving, and the adjacent tooling decisions are still open.

Page through results with limit and offset. The rows returned per request are capped by plan, and requesting more than the cap silently clamps to it rather than erroring:

Plan Max /lookup rows per request
Basic (free)2
Pro ($9/mo)50
Ultra ($29/mo)200
Mega ($79/mo)800

/lookup reflects what has already been scanned, so treat it as a warm start rather than a census of the entire web. The most reliable pipeline uses both: seed from /lookup, then scan your own target list with /analyze/batch to cover domains the index has not seen.

Building a Klaviyo Prospect List End to End

Putting it together: read domains from a file, scan them in batches of 10, keep the Klaviyo users, and write a CSV your CRM can ingest.

import csv
import requests

API = "https://detectzestack.p.rapidapi.com/analyze/batch"
HEADERS = {
    "X-RapidAPI-Key": "YOUR_KEY",
    "X-RapidAPI-Host": "detectzestack.p.rapidapi.com",
    "Content-Type": "application/json",
}
BATCH_SIZE = 10  # API maximum per request


def scan(domains):
    """Scan up to 10 domains, yielding (domain, tech_names, status_code)."""
    resp = requests.post(API, headers=HEADERS, json={"urls": domains}, timeout=60)
    resp.raise_for_status()
    for item in resp.json()["results"]:
        result = item.get("result")
        if not result:
            print(f"  skipped {item['url']}: {item.get('error', 'no result')}")
            continue
        names = [t["name"] for t in result.get("technologies", [])]
        status = result.get("meta", {}).get("status_code")
        yield result["domain"], names, status


def main():
    with open("domains.txt") as f:
        domains = [line.strip() for line in f if line.strip()]

    prospects = []
    for i in range(0, len(domains), BATCH_SIZE):
        chunk = domains[i:i + BATCH_SIZE]
        print(f"Scanning {i + 1}-{i + len(chunk)} of {len(domains)}...")
        for domain, techs, status in scan(chunk):
            if status != 200:
                # The page never loaded, so script-based tech cannot be seen.
                print(f"  {domain}: status {status}, inconclusive")
                continue
            if "Klaviyo" in techs:
                prospects.append({
                    "domain": domain,
                    "platform": next(
                        (t for t in techs
                         if t in ("Shopify", "WooCommerce", "BigCommerce", "Magento")),
                        "unknown",
                    ),
                    "stack": ", ".join(techs),
                })
                print(f"  {domain}: Klaviyo")

    with open("klaviyo_prospects.csv", "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=["domain", "platform", "stack"])
        writer.writeheader()
        writer.writerows(prospects)

    print(f"\n{len(prospects)} Klaviyo stores out of {len(domains)} domains.")


if __name__ == "__main__":
    main()

The status != 200 guard is the part most people leave out, and it is the difference between a clean list and a quietly wrong one. See the caveat below.

Enriching Results With the Rest of the Stack (Shopify, Recharge, Gorgias)

The script above records the whole stack, not just the Klaviyo flag, because the rest of the stack is what makes the outreach land. The same scan that finds Klaviyo also tells you the ecommerce platform underneath it, whether there is a subscriptions app, a helpdesk, a reviews widget, or an A/B testing tool.

That turns a generic opener into a specific one. "I see you are running Klaviyo on Shopify" is table stakes. "I see you are running Klaviyo alongside Intelligems price testing" says you actually looked, and it tells the merchant you understand the problem they are currently working on. The tech stack is the research, and the API does the research for you.

Klaviyo vs Mailchimp vs HubSpot: What the Signal Tells You

All three land in the Marketing automation category, so a category filter catches all of them. What separates them is what each one implies about the company behind it.

Signal What it usually means Who should care
Klaviyo Ecommerce-first. Product catalog, order data, retention budget. Usually paired with Shopify. Shopify apps, reviews, loyalty, SMS, subscriptions, CDP
Mailchimp Generalist email. Often a smaller store or a non-ecommerce business, and sometimes a Klaviyo migration candidate. Anyone selling an upgrade path from basic email
HubSpot B2B motion. Sales pipeline and lead nurture, not cart abandonment. B2B SaaS, sales tooling, RevOps

The pairing is often more informative than the tool. Klaviyo plus Shopify is a DTC brand. HubSpot with no ecommerce platform is a B2B company. Mailchimp on a store doing enough volume to run A/B testing is a store that has outgrown Mailchimp, which is a specific and actionable read that no single-technology filter would surface. Use HubSpot detection and Shopify detection to build these compound filters.

Rate Limits, Caching, and Cost

Plans are the standard DetectZeStack tiers, and every URL scanned counts as one request:

Plan Price Requests / month
BasicFree100
Pro$91,000
Ultra$2910,000
Mega$7950,000

Results are cached for 24 hours by default. A cache hit comes back with "cached": true and a response_ms of 0, which is worth knowing when you are benchmarking: rescanning the same domain twice in a row measures the cache, not the scanner.

The caveat that matters most: check meta.status_code. Klaviyo is detected from the HTML a site returns. If a store answers your scan with a 403 or a 429 instead of its page, there is no HTML to inspect, and Klaviyo will be missing from the results even though the store runs it. The scan does not fail loudly; it just comes back thinner, often with only DNS and TLS signals such as the platform and the CDN. Always treat a non-200 status_code as inconclusive rather than as a negative, or you will silently drop real Klaviyo users from your list and never notice.

Large ecommerce sites sit behind aggressive bot protection, and hammering them concurrently is the fastest way to get a burst of 429s. Space out your batches, retry the inconclusive rows later, and let the cache absorb the repeats. A prospect list built from 200-status scans is worth far more than a bigger one built from noise.

Get Your API Key and Start Detecting

Klaviyo is a rare technographic signal that maps almost directly onto budget: a store running it has revenue worth retaining and has already decided that retention marketing is worth paying for. Detecting it takes one API call, and the same call hands you the rest of the stack for free.

Start with /demo to confirm the signal on a store you already know. Move to /check when you want a boolean, /analyze/batch when you have a list, and /lookup when you want the index to hand you a head start.

Related Reading

Start Finding Klaviyo Stores Today

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

Get Your API Key

Get API updates and tech detection tips

Join the mailing list. No spam, unsubscribe anytime.