# Affiliate Link Health Monitor (`pebbly_thyme/affiliate-link-health-monitor`) Actor

Checks affiliate links, redirect chains, HTTP status, tracking signals, target domains, landing-page text, and changes since the previous run.

- **URL**: https://apify.com/pebbly\_thyme/affiliate-link-health-monitor.md
- **Developed by:** [Wasiliy](https://apify.com/pebbly_thyme) (community)
- **Categories:** SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

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

## Affiliate Link Health Monitor

Automatically monitor affiliate links, redirect chains, destination pages, and tracking signals before broken offers start wasting your traffic.

The Actor checks affiliate URLs in bulk and returns a structured health report for every link.

### What it checks

- Final HTTP status
- Complete redirect chain
- Redirect loops and excessive redirects
- Final destination URL and domain
- Expected affiliate query parameters
- Tracking cookies observed during redirects
- Required text on the landing page
- Forbidden text such as “offer expired” or “page not found”
- Changes compared with the previous run
- Private and local addresses for SSRF protection

### Common use cases

- Monitor affiliate links across content websites
- Detect expired or unavailable offers
- Find redirects leading to an unexpected domain
- Check whether tracking parameters appear in the redirect chain
- Monitor landing pages for important text changes
- Run recurring checks with Apify Schedules
- Export results to JSON, CSV, Excel, Make, n8n, or your own API workflow

### Quick start

1. Open the **Input** tab.
2. Add one or more affiliate URLs.
3. Optionally define expected parameters, destination domains, and page text.
4. Click **Start**.
5. Review the results in the Dataset.

### Example input

```json
{
  "links": [
    {
      "label": "Main partner offer",
      "url": "https://partner.example/click?aff_id=123",
      "expectedAffiliateParams": ["aff_id"],
      "expectedFinalDomains": ["advertiser.example"],
      "requiredText": ["Start free trial"],
      "forbiddenText": ["offer expired", "page not found"]
    }
  ],
  "globalAffiliateParams": [],
  "concurrency": 5,
  "maxRedirects": 10,
  "timeoutSeconds": 20,
  "maxBodyBytes": 1000000,
  "inspectContent": true,
  "warnWhenAffiliateParamsDisappear": false,
  "persistState": true,
  "stateStoreName": "affiliate-link-health-monitor-state",
  "onlyChanged": false,
  "includeBodySnippet": false
}
```

### Input fields

#### `links`

A list of affiliate URLs to check.

Each item can contain:

- `label` — optional name shown in the results
- `url` — affiliate URL to check
- `expectedAffiliateParams` — query parameter names expected in the redirect chain
- `expectedFinalDomains` — allowed final destination domains
- `requiredText` — text that must exist on the final landing page
- `forbiddenText` — text that must not exist on the final landing page

#### `globalAffiliateParams`

Affiliate parameter names applied to every link.

Example:

```json
["aff_id", "subid", "click_id"]
```

#### `concurrency`

Number of links checked in parallel.

A value between 3 and 10 is usually suitable for normal monitoring.

#### `maxRedirects`

Maximum allowed number of redirects for one link.

#### `timeoutSeconds`

Timeout for each HTTP request.

#### `maxBodyBytes`

Maximum amount of landing-page content downloaded for text analysis.

#### `inspectContent`

Enables landing-page text checks.

Set it to `false` when you only need HTTP and redirect information.

#### `warnWhenAffiliateParamsDisappear`

Creates a warning when an affiliate parameter appears earlier in the redirect chain but disappears before the final URL.

Many affiliate networks remove tracking parameters after recording the click, so this option is disabled by default.

#### `persistState`

Stores the previous result for every URL.

This allows the Actor to detect changes between runs.

#### `stateStoreName`

Name of the key-value store used for previous results.

Use a separate store name for unrelated monitoring projects.

#### `onlyChanged`

Outputs only new or changed results.

Use:

```json
"onlyChanged": false
```

for the first run.

After the first successful run, use:

```json
"onlyChanged": true
```

for recurring monitoring.

#### `includeBodySnippet`

Adds a short text snippet from the final landing page to the result.

This is disabled by default.

### Output

Every checked link returns structured data including:

- `status`
- `reasons`
- `httpStatus`
- `inputUrl`
- `finalUrl`
- `redirectCount`
- `redirectChain`
- `redirectLoop`
- `tooManyRedirects`
- `expectedFinalDomains`
- `expectedDomainMatched`
- `expectedAffiliateParams`
- `affiliateParamsFoundAnywhere`
- `affiliateParamsFoundInFinalUrl`
- `affiliateParamsMissingEverywhere`
- `affiliateParamsDisappearedBeforeFinal`
- `trackingCookieNamesObserved`
- `attributionConfidence`
- `requiredTextMissing`
- `forbiddenTextFound`
- `changed`
- `changedFields`
- `previousSummary`
- `responseTimeMs`
- `checkedAt`
- `error`

### Health statuses

#### `healthy`

The link completed successfully and matched all configured checks.

#### `warning`

The link works, but attribution evidence is incomplete or suspicious.

#### `broken`

The link failed one or more important checks.

Possible reasons include:

- HTTP error
- request timeout
- redirect loop
- too many redirects
- unexpected final domain
- missing required text
- forbidden text found
- missing expected affiliate parameter
- invalid or unsafe destination URL

### Attribution confidence

`attributionConfidence` is a technical signal. It does not guarantee that an affiliate commission will be credited.

Possible values:

- `high` — an expected affiliate parameter exists in the final URL
- `medium` — the parameter appeared in the redirect chain and a tracking cookie was observed
- `low` — the parameter appeared, but no additional attribution signal was found
- `none` — the expected parameter was not found
- `not-configured` — no expected parameters were provided

Many affiliate networks remove tracking parameters after recording a click. For this reason, disappearing parameters are not treated as broken by default.

### Scheduled monitoring

For recurring checks:

1. Configure the Actor input.
2. Save the input as an Apify Task.
3. Create a Schedule for the Task.
4. Run it daily or weekly.
5. Enable `onlyChanged` after the first run.
6. Connect the results to a webhook, Make, n8n, email, Telegram, or another automation tool.

For small affiliate websites, a weekly check is often enough.

For large catalogs or frequently changing offers, a daily check may be more useful.

### Example result

```json
{
  "checkedAt": "2026-08-02T10:00:00.000Z",
  "label": "Main partner offer",
  "inputUrl": "https://partner.example/click?aff_id=123",
  "status": "healthy",
  "reasons": [],
  "httpStatus": 200,
  "finalUrl": "https://advertiser.example/pricing?aff_id=123",
  "redirectCount": 2,
  "redirectLoop": false,
  "tooManyRedirects": false,
  "expectedFinalDomains": ["advertiser.example"],
  "expectedDomainMatched": true,
  "expectedAffiliateParams": ["aff_id"],
  "affiliateParamsFoundAnywhere": ["aff_id"],
  "affiliateParamsFoundInFinalUrl": ["aff_id"],
  "affiliateParamsMissingEverywhere": [],
  "affiliateParamsDisappearedBeforeFinal": [],
  "trackingCookieNamesObserved": ["affiliate_click"],
  "attributionConfidence": "high",
  "requiredTextMissing": [],
  "forbiddenTextFound": [],
  "changed": true,
  "changedFields": ["firstRun"],
  "responseTimeMs": 842,
  "error": null
}
```

### Important limitations

This Actor checks technical signals only.

It does not:

- guarantee that an affiliate conversion will be credited
- perform a real purchase or registration
- access affiliate network statistics
- solve CAPTCHAs
- bypass website protection
- execute JavaScript-heavy landing pages
- verify commission data inside an affiliate network account
- imitate users from multiple countries unless external proxy support is added

Some websites may return `403` when accessed from cloud data centers.

A tracking cookie is an additional signal, not proof of successful attribution.

### Security

The Actor blocks:

- localhost
- private IP addresses
- loopback addresses
- link-local addresses
- reserved IP ranges
- URLs containing usernames or passwords
- redirects leading to blocked addresses

This helps reduce SSRF risks when processing public input.

### Recommended monitoring setup

For reliable recurring monitoring:

- use one Task for each website or project
- use a separate `stateStoreName` for each unrelated project
- enable `persistState`
- run the first check with `onlyChanged: false`
- enable `onlyChanged: true` for later runs
- create a webhook for failed Actor runs
- review broken links before removing or replacing them

### Support

When reporting a problem, include:

- the input URL
- the final URL you expected
- the Actor run ID
- the returned status
- the relevant redirect chain
- whether the problem is reproducible

Do not include passwords, private API keys, or confidential affiliate account data.

# Actor input Schema

## `links` (type: `array`):

Each item must contain url. Optional fields: label, expectedAffiliateParams, expectedFinalDomains, requiredText, forbiddenText.

## `globalAffiliateParams` (type: `array`):

Applied to every link, for example aff\_id, subid, click\_id, utm\_source.

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

Number of links checked in parallel.

## `maxRedirects` (type: `integer`):

Maximum redirects

## `timeoutSeconds` (type: `integer`):

Timeout per HTTP request

## `maxBodyBytes` (type: `integer`):

Limits memory and bandwidth when checking landing-page text.

## `inspectContent` (type: `boolean`):

Inspect landing-page text

## `warnWhenAffiliateParamsDisappear` (type: `boolean`):

Many affiliate networks legitimately remove query parameters after recording a click, so this is disabled by default.

## `persistState` (type: `boolean`):

Remember previous results

## `stateStoreName` (type: `string`):

State store name

## `onlyChanged` (type: `boolean`):

Useful for scheduled monitoring. The first run outputs every link.

## `includeBodySnippet` (type: `boolean`):

Include a short landing-page text snippet

## `userAgent` (type: `string`):

User-Agent

## Actor input object example

```json
{
  "links": [
    {
      "label": "Example offer",
      "url": "https://example.com/?aff_id=demo",
      "expectedAffiliateParams": [
        "aff_id"
      ],
      "expectedFinalDomains": [
        "example.com"
      ],
      "requiredText": [
        "Example Domain"
      ],
      "forbiddenText": [
        "offer expired"
      ]
    }
  ],
  "globalAffiliateParams": [],
  "concurrency": 5,
  "maxRedirects": 10,
  "timeoutSeconds": 20,
  "maxBodyBytes": 1000000,
  "inspectContent": true,
  "warnWhenAffiliateParamsDisappear": false,
  "persistState": true,
  "stateStoreName": "affiliate-link-health-monitor-state",
  "onlyChanged": false,
  "includeBodySnippet": false,
  "userAgent": "AffiliateLinkHealthMonitor/0.1 (+https://apify.com/)"
}
```

# Actor output Schema

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

HTTP status, final URL, redirect chain, tracking evidence, content checks, and changes since the previous run.

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

Counts of healthy, warning, broken, changed, and emitted results.

# 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 = {
    "links": [
        {
            "label": "Example offer",
            "url": "https://example.com/?aff_id=demo",
            "expectedAffiliateParams": [
                "aff_id"
            ],
            "expectedFinalDomains": [
                "example.com"
            ],
            "requiredText": [
                "Example Domain"
            ],
            "forbiddenText": [
                "offer expired"
            ]
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pebbly_thyme/affiliate-link-health-monitor").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 = { "links": [{
            "label": "Example offer",
            "url": "https://example.com/?aff_id=demo",
            "expectedAffiliateParams": ["aff_id"],
            "expectedFinalDomains": ["example.com"],
            "requiredText": ["Example Domain"],
            "forbiddenText": ["offer expired"],
        }] }

# Run the Actor and wait for it to finish
run = client.actor("pebbly_thyme/affiliate-link-health-monitor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "links": [
    {
      "label": "Example offer",
      "url": "https://example.com/?aff_id=demo",
      "expectedAffiliateParams": [
        "aff_id"
      ],
      "expectedFinalDomains": [
        "example.com"
      ],
      "requiredText": [
        "Example Domain"
      ],
      "forbiddenText": [
        "offer expired"
      ]
    }
  ]
}' |
apify call pebbly_thyme/affiliate-link-health-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=pebbly_thyme/affiliate-link-health-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/8XXy4KvOhk2E8Js3v/builds/ygcANXWd7W9xHSRnf/openapi.json
