# Wayback Tracking ID History: GA4, GTM, UA, Ads (`income_wizard/wayback-tracking-id-history`) Actor

See which Google Analytics, Tag Manager, Google Ads and other tracking IDs a website used in the past and when it added or dropped each, from Wayback Machine copies of its home page.

- **URL**: https://apify.com/income_wizard/wayback-tracking-id-history.md
- **Developed by:** [Illia Boyko](https://apify.com/income_wizard) (community)
- **Categories:** SEO tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$20.00 / 1,000 website analyzeds

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Wayback Tracking ID History

Find out **which analytics, ad-pixel and tag-manager IDs a website used in the past, and when it added or dropped each one**. The actor reads archived copies of a site's home page from the Internet Archive (Wayback Machine), takes the IDs out of each copy and gives you one row per website with a timeline for every ID. It looks for 53 kinds of tool; the test runs returned an ID for 25 of them: Google Tag Manager (`GTM-`), Google Analytics 4 (`G-`), Universal Analytics (`UA-`), Google tag (`GT-`), Google Ads (`AW-`), Meta Pixel, LinkedIn Insight, Pinterest, X and Reddit pixels, Microsoft Advertising UET, Hotjar, Mixpanel, Heap, PostHog, HubSpot, Klaviyo, Intercom, LiveChat, OneTrust, CookieYes, Optimizely, Sentry, Stripe and Tealium.

**Who it is for**

- OSINT and fraud researchers who link sites through a shared old analytics or ad account: a former owner may have left a `UA-` or `GTM-` ID in the page.
- Agencies and sales teams: when did this company switch tag manager, drop Universal Analytics, or start a new ad pixel?
- Buyers of expired or acquired domains who want to see which accounts the site belonged to before.

### What you get

One dataset row per website:

| Field | Meaning |
|---|---|
| `history` | one entry per ID (a tool found without an ID, such as OneTrust or Stripe.js, has `id: null`; 4 of 90 entries in our 20-site test): tool, `id`, `firstSeen`, `lastSeen`, `status` (`current` or `removed`), `snapshotsSeen`, `lastSnapshotWithoutIt` (the added-after date: the last copy that did not have it) and `firstSnapshotWithoutIt` (the removed-by date: the first copy without it), plus `firstSeenArchive` and `lastSeenArchive`, the archive links you can open to check |
| `changes` | per archived copy: IDs added and removed compared with the previous copy |
| `snapshots` | the IDs found in each copy |
| `firstSnapshot`, `lastSnapshot`, `snapshotsRead` | the span and number of copies read |

Example (shortened, `allbirds.com`, 8 years, 2 copies a year):

```json
{"domain": "allbirds.com", "snapshotsRead": 16, "firstSnapshot": "2019-01-01", "lastSnapshot": "2026-07-01",
 "history": [
  {"tool": "Universal Analytics (legacy)", "id": "UA-73307718-1", "firstSeen": "2019-01-01", "lastSeen": "2022-01-01",
   "status": "removed", "snapshotsSeen": 7, "firstSnapshotWithoutIt": "2022-07-01",
   "firstSeenArchive": "https://web.archive.org/web/20190101.../http://allbirds.com/"},
  {"tool": "Google Tag Manager", "id": "GTM-NJVZ6WQ", "firstSeen": "2019-07-02", "lastSeen": "2024-01-02",
   "status": "removed", "snapshotsSeen": 10, "lastSnapshotWithoutIt": "2019-01-01", "firstSnapshotWithoutIt": "2024-07-02"}],
 "changes": [{"snapshot": "2019-07-02", "added": ["gtm:GTM-NJVZ6WQ"], "removed": ["gtm:GTM-M55BQF2", "gtm:GTM-W4HDTKM"]}]}
```

### Input

```json
{"domains": ["allbirds.com", "nytimes.com"], "years": 8, "snapshotsPerYear": 2}
```

- `years` (1-25, default 8) and `snapshotsPerYear` (1, 2, 3, 4, 6 or 12, default 2; any other number is read as 2): how many archived copies are read. More copies narrow the date range of every change and make the run longer.
- `concurrency` (default 2) and `maxDomains` (default 200).

### Price

**$0.02 per website** with at least one readable archived copy (event `domain-analyzed`). A website with no readable copy, or an invalid domain, is not charged. A website with copies but no IDs in them is charged: the copies were read.

### What it can and cannot see (read this)

- **Home page HTML only.** An ID is found when it is written in the HTML of the archived home page. IDs that a site loads from a JavaScript file or from inside a Google Tag Manager container are not in the page and are not returned: the Internet Archive does not keep those containers reliably. So `status: removed` means "no longer in the page HTML", and the ID may have moved into a tag manager.
- **Sampled, not complete.** The actor reads evenly spaced copies, not every copy. A change is dated to the range between two copies (`lastSnapshotWithoutIt` to `firstSeen`), not to the day.
- **Not every site is archived.** Sites with no copy in the chosen years get no row data and no charge.
- **Speed.** The Internet Archive refuses clients that send many requests, so the actor sends about one request every 1.5 seconds and waits and retries when it is throttled (429, 5xx, connection errors). One website with 2 copies a year over 8 years took 35 seconds; a run of 20 websites took 593 seconds (about 10 minutes) in our test, one of them excluded from the archive. A site the archive refuses (excluded, blocked: HTTP 400, 401, 403, 410, 451) is not retried: that date is skipped in seconds, and a site where every date is refused is returned as "no readable copy" without a charge.
- Only data the Internet Archive publishes is used. No login, no proxy, no browser.

### Not the same as

Actors that list Wayback snapshots (dates, status codes, digests) leave you to download and read every page yourself. Actors that read BuiltWith give tool names and first/last detected dates from BuiltWith's own data, not the account IDs found in the archived page. This actor returns the **IDs**, with the archive link of the copy where each was first and last seen so you can check it.

# Actor input Schema

## `domains` (type: `array`):

Domains, one per line, for example example.com. The home page of each is read from the Internet Archive.

## `years` (type: `integer`):

How far back to sample archived copies, counted from today.

## `snapshotsPerYear` (type: `integer`):

How many archived copies of the home page are read per year (1, 2, 3, 4, 6 or 12). More copies narrow the date range in which an ID was added or removed, and make the run longer.

## `concurrency` (type: `integer`):

How many websites are read at once. Keep it low: the Internet Archive slows down clients that send many requests.

## `maxDomains` (type: `integer`):

Stop after this many websites.

## Actor input object example

```json
{
  "domains": [
    "allbirds.com",
    "nytimes.com"
  ],
  "years": 8,
  "snapshotsPerYear": 2,
  "concurrency": 2,
  "maxDomains": 200
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "domains": [
        "allbirds.com",
        "nytimes.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("income_wizard/wayback-tracking-id-history").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 = { "domains": [
        "allbirds.com",
        "nytimes.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("income_wizard/wayback-tracking-id-history").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 '{
  "domains": [
    "allbirds.com",
    "nytimes.com"
  ]
}' |
apify call income_wizard/wayback-tracking-id-history --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,income_wizard/wayback-tracking-id-history"
        }
    }
}
```

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/cBJMCVKQ0cfoafLR8/builds/fRvYAcVzb7XZhuLfm/openapi.json
