# Ad Activity Tracker — Companies Running Ads & Ad Volume (`inovaflow/ad-activity-tracker`) Actor

Which companies are running ads right now, how many active ads each one has, on which platforms, since when — and whether that is ramping, slowing or just stopped. One advertiser row per company with creatives, landing pages, momentum vs your last run and who to sell to. Dataset-only, MCP-ready.

- **URL**: https://apify.com/inovaflow/ad-activity-tracker.md
- **Developed by:** [inovaflow](https://apify.com/inovaflow) (community)
- **Categories:** Lead generation, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 advertiser checks

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Ad Activity Tracker — Companies Running Ads & Ad Volume

**If a company suddenly has 40 live ads where it had four, something changed inside that company.** A new
budget, a new growth lead, a launch, a funding round being spent. Public ad libraries will tell you that a
company *has* ads. They will not tell you how many, on which platforms, since when, or whether that number
is going up — which is the part that makes it a reason to call.

This Actor answers all of it, as one row per company: **how many ads are live right now**, on which
platforms, how long they have been running, what the ads say, where they point — and **what changed since
your last run**.

***

### Who it is for

- **Outbound teams** — "ramping ads" is a warm trigger: the budget is moving and the growth lead is under
  pressure to make it work. Every row tells you who to call and gives you the opening line.
- **AI / GTM agents** — one call, a flat dataset, no login and no key. `activeAdCount`, `momentum`,
  `momentumTrend`, `signalTags`, `sellTo`, `whyNow` are all on the row.
- **Competitive intelligence** — track rivals' ad volume, creatives and landing pages week over week.
- **Agencies** — prove a prospect is spending (and on what) before the first call; spot the accounts that
  just switched paid off.
- **Investors and analysts** — paid-media volume as a demand-side indicator across a portfolio or a market.

***

### What makes it different

| | Typical ad-library scraper | This Actor |
| --- | --- | --- |
| Row shape | one row per **ad** | one row per **company** |
| The number | you count the rows yourself | `activeAdCount` — the library's own total for that advertiser |
| Change over time | none — every run is a fresh dump | `momentum`, `momentumPct`, `momentumTrend`, platforms added/dropped |
| Platform coverage | whatever that one library shows | live ads **plus** every ad platform the company's own site is tagged for |
| Output | creatives | creatives **plus** the signal: tags, who to sell to, why now, a 0–100 score |

***

### What you get per company

```jsonc
{
  "company": "Ramp",
  "domain": "ramp.com",
  "isAdvertising": true,
  "activeAdCount": 209,
  "platforms": ["meta", "google-ads", "linkedin"],
  "platformsWithLiveAds": ["meta"],
  "platformsOnSite": ["google-ads", "linkedin"],
  "momentum": 43,
  "momentumPct": 26,
  "momentumTrend": "ramping",
  "previousActiveAdCount": 166,
  "newPlatformsSinceLastRun": ["linkedin"],
  "adsStartedLast7d": 12,
  "adTenureDays": 207,
  "sampleCreatives": [{ "title": "…", "body": "…", "cta": "Sign up", "landingPage": "https://ramp.com/…" }],
  "landingPages": ["https://ramp.com/pricing", "…"],
  "signalScore": 83,
  "signalTags": ["running-ads", "high-volume-advertiser", "ramping-ads", "multi-platform-advertiser",
                 "added-linkedin", "testing-new-creatives"],
  "sellTo": ["Head of Performance Marketing", "Head of Growth", "VP Marketing", "CMO"],
  "whyNow": "Active ads went from 166 to 209 (+26%) since the previous check — they are putting money behind Meta right now."
}
```

Three dataset views are built in: **Ad activity by company**, **What changed** (the delta) and
**Creatives & landing pages**.

***

### Use it in three ways

**1 · Watch your target accounts or competitors.**

```json
{ "companies": ["gong.io", "ramp.com", "clay.com"], "countries": ["US"] }
```

Domains work best — an ad that sends traffic to the company's own site proves which advertiser page belongs
to it. Brand names work too, and you can paste a Meta page id as `page:1234567890`.

**2 · Discover who is advertising in your category.** Leave the company list empty and give keywords:

```json
{ "keywords": ["AI note taker", "project management software"], "countries": ["US", "GB"] }
```

You get the companies buying ads against those words, ranked by how much they are spending attention on it.

**3 · A scheduled feed of what changed.** Set a `watchId` and schedule it daily or weekly. The first run
stores the baseline; from then on every row carries `momentum`, `momentumTrend` and the platforms added or
dropped. Filter on `ramping-ads`, `new-to-paid` or `paused-ads` and you have a trigger feed.

***

### How the signal is built

- **Count, don't sample.** The row reports the advertiser's own total from the public library, not the
  number of ads that happened to fit on one page. `activeAdCountIsMinimum` tells you on the rare occasion
  it is a floor instead.
- **Two kinds of evidence.** Live ads prove volume; a live conversion tag on the company's own site proves
  they buy on platforms no library counts (Google Ads, LinkedIn, TikTok, Microsoft, Reddit and more). Most
  companies load those through a tag manager, so the container is read as well — which is how a site that
  looks untagged turns out to be running six platforms.
- **Remember, then diff.** Each watch keeps a private memory of every advertiser's ad count and platforms.
  Ramping, slowing, paused, resumed and new-to-paid all come from that, and small wobbles are deliberately
  reported as `steady` rather than as fake movement.

***

### Chain it

| Then run | To get |
| --- | --- |
| **Decision-Maker Finder** | the actual people in `sellTo` at each advertiser, with work e-mails |
| **Recently Funded Companies** | the raise that paid for the ad ramp |
| **Hiring Intent Scraper** | whether they are also hiring the team to run it |
| **Technology Lookup** | the rest of their stack |

***

### Notes

- No login, no cookies, no API key, and no other paid Actor is ever started.
- Ad libraries report **per country** — the same advertiser can have 200 live ads in one country and none in
  another. The country list is part of the question you are asking.
- A company with no live ads in the library still gets a row: "not advertising here" is usually the answer
  you wanted, and the site tags often show they buy elsewhere.
- Apify residential proxy is the default and is strongly recommended; ad libraries rate-limit datacenter
  ranges hard.

### Pricing

Pay per event: you pay per company checked and delivered. See `PRICING.md`.

# Actor input Schema

## `companies` (type: `array`):

One per line: a domain (`gong.io`) or a brand name (`Gong`). A domain is matched most reliably, because ads that point at the company's own site prove which advertiser it is. You can also paste a Meta page id as `page:1234567890`.

## `keywords` (type: `array`):

Used only when the company list is empty: find the companies running ads that mention these words, e.g. `project management software`, `CRM for startups`. Each keyword is searched in each country below.

## `countries` (type: `array`):

Two-letter country codes, one per line — ad libraries report per country, so `US` and `DE` can give very different counts for the same advertiser. The first country is used for the company watchlist.

## `useAdLibrary` (type: `boolean`):

Reads the public ad library for the exact number of ads each advertiser is running right now, plus the creatives, the landing pages, the surfaces and the dates. This is the source of the volume number — keep it on.

## `useSiteScan` (type: `boolean`):

Reads the company's own homepage and lists the ad platforms it is tagged for — Google Ads, LinkedIn, TikTok, Reddit, Microsoft, Pinterest and more. Ad libraries cannot count those, but a live conversion tag proves the company is paying for them. Free, one request per company.

## `includeInactiveAds` (type: `boolean`):

By default only ads that are live right now are counted — that is what makes the number a signal. Turn this on to include stopped ads, e.g. for a historical teardown of a competitor's campaigns.

## `onlyAdvertisers` (type: `boolean`):

Drop companies where no live ads and no ad tags were found. Off by default, because "they are not advertising" is often the answer you asked for.

## `minActiveAds` (type: `integer`):

Only report companies running at least this many ads right now. Leave at 0 to report everyone checked.

## `maxCompanies` (type: `integer`):

Cap on delivered rows (highest signal score first). Also caps what you pay.

## `maxCreatives` (type: `integer`):

How many example ads to keep on each row (newest first, one per landing page). Set to 0 for counts only.

## `watchId` (type: `string`):

Optional name for this watch, e.g. `competitors-us`. Runs sharing a Watch ID share the ad-count history, so an agent can poll one watch on a schedule. Leave empty to derive it from the companies, keywords and countries.

## `maxAdvertisersPerKeyword` (type: `integer`):

How many advertisers to keep from each keyword search before the exact ad counts are read.

## `maxConcurrency` (type: `integer`):

Concurrent ad-library reads. Keep it low — the library rate-limits an IP that reads too fast, and each session has to pass a check first.

## `proxyConfiguration` (type: `object`):

The ad library rate-limits datacenter ranges, so Apify residential proxy (included in Apify Proxy) is the default and is strongly recommended. The website scan always goes direct.

## Actor input object example

```json
{
  "companies": [
    "gong.io",
    "Ramp",
    "page:1234567890"
  ],
  "keywords": [
    "project management software",
    "AI note taker"
  ],
  "countries": [
    "US",
    "GB",
    "DE"
  ],
  "useAdLibrary": true,
  "useSiteScan": true,
  "includeInactiveAds": false,
  "onlyAdvertisers": false,
  "minActiveAds": 0,
  "maxCompanies": 100,
  "maxCreatives": 5,
  "watchId": "competitors-us",
  "maxAdvertisersPerKeyword": 15,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `advertisers` (type: `string`):

One row per company: active ad count, platforms, momentum vs your last run, signal score and tags.

## `momentum` (type: `string`):

Ramping, slowing, paused and new-to-paid companies, with the platforms added or dropped since the previous run.

## `creatives` (type: `string`):

What each advertiser is actually running: ad copy, calls to action and the pages the ads point at.

## `summary` (type: `string`):

Counts, totals, platform breakdown, per-source report and the watch id.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "companies": [
        "notion.so",
        "gong.io"
    ],
    "countries": [
        "US"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("inovaflow/ad-activity-tracker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "companies": [
        "notion.so",
        "gong.io",
    ],
    "countries": ["US"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("inovaflow/ad-activity-tracker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "companies": [
    "notion.so",
    "gong.io"
  ],
  "countries": [
    "US"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call inovaflow/ad-activity-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,inovaflow/ad-activity-tracker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/vYivjFm6N6SEhjqST/builds/h7YKDYBe0b9Hc5a0w/openapi.json
