# Affiliate & Tracking Link Redirect Tracer (`xtracto/affiliate-redirect-tracer`) Actor

Follow any short or affiliate link hop by hop to its real destination. Returns the full redirect chain, the affiliate network, tracking IDs, tracker domains, cloaking signals, and dead-link detection. No account needed.

- **URL**: https://apify.com/xtracto/affiliate-redirect-tracer.md
- **Developed by:** [Farhan Febrian Nauval](https://apify.com/xtracto) (community)
- **Categories:** SEO tools, Automation
- **Stats:** 3 total users, 2 monthly users, 95.5% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.33 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Affiliate & Tracking Link Redirect Tracer

Paste any short link, affiliate link or ad link and get the **full journey to its real destination** — every hop, every tracking ID picked up along the way, the affiliate network behind it, and whether the link is still alive.

### Why use this actor

- **No account, no key, no login** — paste links, press Run.
- **See every single hop**, not just the last one: status code, next address, response time, and the cookies each hop drops on the visitor.
- **Catches hidden redirects** that a simple link checker misses — bounces built into the page itself (automatic page refresh and small in-page scripts), which is exactly how cloaked links hide their destination.
- **Identifies the affiliate network** (Amazon Associates, AliExpress Portals, Awin, CJ, Impact, Rakuten, ShareASale, Skimlinks, ClickBank, Partnerize, Admitad, TradeDoubler, Pepperjam, Sovrn, Geniuslink, FlexOffers and more) — and stays honest, returning `null` when it cannot prove one.
- **Pulls out every tracking ID** in the chain (`tag`, `aff_id`, `subid`, `clickid`, `irclickid`, `gclid`, `fbclid`, `utm_*`, …) and tells you which hop each one appeared on — perfect for checking that your partner IDs survive to the merchant.
- **Flags dead and hijacked links**: expired, deactivated and removed links come back as a clean record with the real status code, so you can audit thousands of links and sort the broken ones.
- **Stops safely** on redirect loops and on your hop limit, and says exactly why it stopped.
- Clean, stable JSON for spreadsheets, dashboards and databases. Export to JSON, CSV or Excel, or run it on a schedule.

Typical uses: affiliate-compliance audits ("where does this link *really* go?"), spotting cloaked or hijacked links in your own content, ad-fraud checks, building an inventory of the tracking companies a campaign passes through, and monitoring partner links for breakage.

### How it works

1. Add the links you want checked (short links, affiliate links, ad links, or plain URLs).
2. The actor opens the first link like a real visitor would and **records what came back** instead of blindly jumping to the end.
3. It keeps stepping forward — normal redirects, automatic page refreshes and simple in-page bounces are all followed — recording each stop, until it reaches a page that does not redirect any further.
4. From the finished chain it works out the destination, the merchant, the affiliate network, the tracking IDs and the intermediate tracking companies, and flags anything that looks cloaked.
5. One record per link lands in your dataset with the summary at the top and the full hop-by-hop detail underneath.

You do not manage any scrapers, browsers or servers — retries, timeouts, loop protection and hop limits are handled for you.

### Input

```json
{
  "startUrls": [
    { "url": "https://amzn.to/3QZv1kM" },
    { "url": "https://s.click.aliexpress.com/e/_DdJcHZv" },
    { "url": "https://bit.ly/3xyzabc" }
  ],
  "maxHops": 15,
  "timeoutSeconds": 20,
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
  "followMetaRefresh": true,
  "followJsRedirects": true,
  "maxItems": 100,
  "maxConcurrency": 4
}
```

| Field | Type | Description |
| --- | --- | --- |
| `startUrls` | array | The links to trace. One output record per link. |
| `maxHops` | integer | How many redirects to follow before stopping (default `15`). |
| `timeoutSeconds` | integer | How long to wait for each single hop (default `20`). |
| `userAgent` | string | Which browser to appear as. Some links send desktop, mobile and bot visitors to different places, so this can change the destination. Leave blank for the built-in desktop Chrome identity. |
| `followMetaRefresh` | boolean | Follow redirects hidden in the page as an automatic refresh (default `true`). |
| `followJsRedirects` | boolean | Follow simple in-page script redirects (default `true`). |
| `maxItems` | integer | Safety cap on links traced per run (default `100`). |
| `maxConcurrency` | integer | How many links are followed at the same time (default `4`). |
| `proxyConfiguration` | object | Optional. Datacenter is enough for most links; choose a residential proxy and country when you need a specific market's destination. |

### Output

#### A live affiliate link — 4 hops, tracking IDs collected along the way

`https://s.click.aliexpress.com/e/_DdJcHZv` (hops truncated for readability)

```json
{
  "_input": "https://s.click.aliexpress.com/e/_DdJcHZv",
  "_source": "S1-trace",
  "_scrapedAt": "2026-07-25T13:04:06Z",
  "startUrl": "https://s.click.aliexpress.com/e/_DdJcHZv",
  "startHost": "s.click.aliexpress.com",
  "startDomain": "aliexpress.com",
  "finalUrl": "https://best.aliexpress.com/?UTABTest=aliabtest138740_46370&commercial_type=bestPage&hc_1214_tag=ByAffPage&aff_fcid=4c63c50c6b9746b798efc7ee9f1769ea-1784984646392-06593-_pz9sEiR&aff_fsk=_pz9sEiR&aff_platform=portals-promotion&sk=_pz9sEiR&aff_trace_key=4c63c50c6b9746b798efc7ee9f1769ea-1784984646392-06593-_pz9sEiR&terminal_id=c2a3f72b218749efbc471c4ff926c7dd&pageId=11404771&OLP=1133102008_f_group1&o_s_id=1133102008",
  "finalStatus": 200,
  "finalHost": "best.aliexpress.com",
  "merchantDomain": "aliexpress.com",
  "finalPageTitle": "MoboMarket - Belanja Online untuk Elektronik Populer, Mode, Rumah & Taman, Mainan & Olahraga, Mobil dan Lainnya.",
  "totalHops": 4,
  "redirectCount": 3,
  "stopReason": "final",
  "isDeadLink": false,
  "affiliateNetwork": "AliExpress Portals",
  "affiliateNetworkEvidence": "host:s.click.aliexpress.com@hop0",
  "affiliateIds": {
    "aff_short_key": "_pz9sEiR",
    "aff_fcid": "4c63c50c6b9746b798efc7ee9f1769ea-1784984646392-06593-_pz9sEiR",
    "aff_fsk": "_pz9sEiR",
    "aff_platform": "portals-promotion",
    "aff_trace_key": "4c63c50c6b9746b798efc7ee9f1769ea-1784984646392-06593-_pz9sEiR"
  },
  "affiliateIdSources": [
    { "param": "aff_short_key", "value": "_pz9sEiR", "hopIndex": 2, "host": "s.click.aliexpress.com" },
    { "param": "aff_trace_key", "value": "4c63c50c6b9746b798efc7ee9f1769ea-1784984646392-06593-_pz9sEiR", "hopIndex": 3, "host": "best.aliexpress.com" }
  ],
  "trackerDomains": ["s.click.aliexpress.com"],
  "isCloaked": false,
  "cloakingSignals": [],
  "redirectTypes": ["http-3xx", "http-3xx", "http-3xx", "final"],
  "totalElapsedMs": 578,
  "hops": [
    {
      "hopIndex": 0,
      "url": "https://s.click.aliexpress.com/e/_DdJcHZv",
      "host": "s.click.aliexpress.com",
      "domain": "aliexpress.com",
      "method": "GET",
      "statusCode": 302,
      "redirectType": "http-3xx",
      "location": "https://best.aliexpress.com",
      "nextUrl": "https://best.aliexpress.com",
      "elapsedMs": 125,
      "contentType": null,
      "server": "Tengine",
      "via": null,
      "cookiesSet": [
        { "name": "xman_us_f", "value": "x_l=1&acs_rt=c2a3f72b218749efbc471c4ff926c7dd" },
        { "name": "XSRF-TOKEN", "value": "408f82d2-d1dc-4ac2-ab81-f8bdae2cd8d4" }
      ],
      "trackingParams": {},
      "browserProfile": "Chrome (desktop)"
    },
    {
      "hopIndex": 1,
      "url": "https://best.aliexpress.com",
      "host": "best.aliexpress.com",
      "domain": "aliexpress.com",
      "method": "GET",
      "statusCode": 302,
      "redirectType": "http-3xx",
      "location": "https://s.click.aliexpress.com/deep_link.htm?aff_short_key=_pz9sEiR&dl_target_url=https%3A%2F%2Fbest.aliexpress.com%2F%3Faff_platform%3Ddefault%26commercial_type%3DbestPage%26hc_1214_tag%3DByAffPage",
      "elapsedMs": 94,
      "server": "Tengine",
      "trackingParams": {},
      "browserProfile": "Chrome (desktop)"
    }
  ]
}
```

*(the last two hops are omitted above — … 2 more)*

#### A hidden in-page redirect (cloaking signal)

`https://l.facebook.com/l.php?u=https%3A%2F%2Fexample.com%2F` — the second hop answers `200 OK` but pushes the visitor onward with an automatic page refresh, which is caught and followed:

```json
{
  "_input": "https://l.facebook.com/l.php?u=https%3A%2F%2Fexample.com%2F",
  "_source": "S1-trace",
  "_scrapedAt": "2026-07-25T13:04:07Z",
  "startUrl": "https://l.facebook.com/l.php?u=https%3A%2F%2Fexample.com%2F",
  "startHost": "l.facebook.com",
  "startDomain": "facebook.com",
  "finalUrl": "https://www.facebook.com/flx/warn/?u=https%3A%2F%2Fexample.com%2F&h=AUCLpUtzNyqOuafKkRCFvb-AEwTJZ2W3EEiTn1Mm9sTJfsMqd8LU-SyBcI6xgjhXvFVJAfaC5OeorfWLM-2q3FL5-C10PrjKml3JteDi4tDFdS6eD9LfHVo&_fb_noscript=1",
  "finalStatus": 200,
  "finalHost": "www.facebook.com",
  "merchantDomain": "facebook.com",
  "finalPageTitle": "Leaving Facebook",
  "totalHops": 3,
  "redirectCount": 2,
  "stopReason": "final",
  "isDeadLink": false,
  "affiliateNetwork": "Generic link shortener",
  "affiliateNetworkEvidence": "host:l.facebook.com@hop0",
  "affiliateIds": {},
  "trackerDomains": ["l.facebook.com"],
  "isCloaked": true,
  "cloakingSignals": ["meta_refresh_hop"],
  "redirectTypes": ["http-3xx", "meta-refresh", "final"],
  "totalElapsedMs": 890,
  "hops": [
    { "hopIndex": 0, "statusCode": 302, "redirectType": "http-3xx", "host": "l.facebook.com", "elapsedMs": 250, "cookiesSet": [{ "name": "datr", "value": "R7Rkat8rU_1dhMVGjfKLxY6I" }] },
    { "hopIndex": 1, "statusCode": 200, "redirectType": "meta-refresh", "host": "www.facebook.com", "elapsedMs": 344, "cookiesSet": [] },
    { "hopIndex": 2, "statusCode": 200, "redirectType": "final", "host": "www.facebook.com", "elapsedMs": 296, "cookiesSet": [{ "name": "noscript", "value": "1" }], "pageTitle": "Leaving Facebook" }
  ]
}
```

#### A shortener that shows a preview page instead of forwarding

`https://bit.ly/3xyzabc` — the destination is read off the preview page, then followed; the destination itself turns out to be gone:

```json
{
  "_input": "https://bit.ly/3xyzabc",
  "_source": "S1-trace",
  "_scrapedAt": "2026-07-25T13:04:08Z",
  "startUrl": "https://bit.ly/3xyzabc",
  "finalUrl": "https://drive.google.com/drive/folders/1h58cRaUSsDuzotaMOSMsfMkwGTwdpFBR?usp=sharing",
  "finalStatus": 404,
  "finalHost": "drive.google.com",
  "merchantDomain": "google.com",
  "finalPageTitle": "Error 404 (Tidak Ditemukan)!!1",
  "totalHops": 2,
  "redirectCount": 1,
  "stopReason": "final",
  "isDeadLink": true,
  "affiliateNetwork": "Generic link shortener",
  "affiliateNetworkEvidence": "host:bit.ly@hop0",
  "affiliateIds": {},
  "trackerDomains": ["bit.ly"],
  "isCloaked": true,
  "cloakingSignals": ["interstitial_page_hop"],
  "redirectTypes": ["interstitial-link", "final"],
  "totalElapsedMs": 1590,
  "hops": [
    {
      "hopIndex": 0,
      "url": "https://bit.ly/3xyzabc",
      "host": "bit.ly",
      "statusCode": 200,
      "redirectType": "interstitial-link",
      "nextUrl": "https://drive.google.com/drive/folders/1h58cRaUSsDuzotaMOSMsfMkwGTwdpFBR?usp=sharing",
      "elapsedMs": 389,
      "server": "nginx",
      "via": "1.1 google",
      "cookiesSet": [{ "name": "_bit", "value": "q6pd46-aa547ab7874fd7aea7-00k" }],
      "browserProfile": "Chrome (desktop)"
    },
    { "hopIndex": 1, "statusCode": 404, "redirectType": "final", "host": "drive.google.com", "elapsedMs": 375, "pageTitle": "Error 404 (Tidak Ditemukan)!!1" }
  ]
}
```

#### A dead link — reported, never hidden

`https://bit.ly/zzzzzzzzzzzzzz`

```json
{
  "_input": "https://bit.ly/zzzzzzzzzzzzzz",
  "_source": "S1-trace",
  "_scrapedAt": "2026-07-25T13:04:08Z",
  "startUrl": "https://bit.ly/zzzzzzzzzzzzzz",
  "finalUrl": "https://bit.ly/zzzzzzzzzzzzzz",
  "finalStatus": 410,
  "finalHost": "bit.ly",
  "merchantDomain": "bit.ly",
  "finalPageTitle": "Bitly | Link Deactivated | 410",
  "totalHops": 1,
  "redirectCount": 0,
  "stopReason": "final",
  "isDeadLink": true,
  "affiliateNetwork": "Generic link shortener",
  "affiliateNetworkEvidence": "host:bit.ly@hop0",
  "affiliateIds": {},
  "trackerDomains": [],
  "isCloaked": false,
  "cloakingSignals": [],
  "redirectTypes": ["final"],
  "totalElapsedMs": 296,
  "hops": [
    {
      "hopIndex": 0,
      "url": "https://bit.ly/zzzzzzzzzzzzzz",
      "host": "bit.ly",
      "statusCode": 410,
      "redirectType": "final",
      "elapsedMs": 296,
      "contentType": "text/html",
      "server": "nginx",
      "via": "1.1 google",
      "cookiesSet": [],
      "trackingParams": {},
      "pageTitle": "Bitly | Link Deactivated | 410"
    }
  ]
}
```

#### Summary fields

| Field | Type | Description |
| --- | --- | --- |
| `_input` / `_scrapedAt` / `_source` | string | The link you submitted, when it was checked (UTC), and which method produced the record. |
| `startUrl` / `startHost` / `startDomain` | string | The submitted link and the site it starts on. |
| `finalUrl` / `finalHost` / `merchantDomain` | string | Where the chain ended up, and the destination's main domain. |
| `finalStatus` | integer | Status code of the last stop (`200` alive, `404` / `410` dead, and so on). |
| `finalPageTitle` | string | Title of the destination page when it is a readable page. |
| `totalHops` / `redirectCount` | integer | Number of stops, and how many of them were redirects. |
| `stopReason` | string | `final`, `max_hops`, `loop`, `timeout` or `error`. |
| `isDeadLink` | boolean | `true` when the chain ends on an error status. |
| `affiliateNetwork` | string | The network behind the link, `Generic link shortener`, or `null` when it cannot be proven. |
| `affiliateNetworkEvidence` | string | Exactly what proved it (which host or which tracking value, and at which hop). |
| `affiliateIds` | object | Every tracking ID found anywhere in the chain, as name → value. |
| `affiliateIdSources` | array | The same IDs with the hop number and host where each first appeared. |
| `trackerDomains` | array | The intermediate companies the visitor passes through before the destination. |
| `isCloaked` / `cloakingSignals` | boolean / array | Whether the chain hides its destination, and why: `meta_refresh_hop`, `js_redirect_hop`, `interstitial_page_hop`, `network_domain_mismatch`, `unexpected_cross_domain`. |
| `redirectTypes` | array | The kind of each stop, in order. |
| `totalElapsedMs` | integer | Total time the whole chain took. |
| `hops` | array | Full detail of every stop — see below. |

#### Hop fields

| Field | Type | Description |
| --- | --- | --- |
| `hopIndex` | integer | Position in the chain, starting at 0. |
| `url` / `host` / `domain` | string | The address requested at this stop. |
| `method` | string | Always `GET`. |
| `statusCode` | integer | The status returned at this stop. |
| `redirectType` | string | `http-3xx` (normal redirect), `meta-refresh` (automatic page refresh), `js-location` (in-page script), `interstitial-link` (destination read off a preview page), `final` (no further redirect), or `error`. |
| `location` / `nextUrl` | string | The forwarding address exactly as given, and the full address actually used next. |
| `elapsedMs` | integer | Response time for this stop. |
| `contentType` / `server` / `via` | string | Response details of the stop, as sent. |
| `cookiesSet` | array | Cookies dropped at this stop (name and value) — the tracking companies' own attribution cookies. |
| `trackingParams` | object | Tracking values present in this stop's address. |
| `browserProfile` | string | Which browser identity was used for this stop. |
| `pageTitle` | string | Title of the page, on the final stop. |
| `error` / `errorDetail` | string | Present only when this stop could not be reached. |

If a link cannot be processed at all, the actor emits `{_input, _source, _scrapedAt, _error, _errorDetail}` instead of silently skipping it. A dead link is **not** an error — it is a normal record with `isDeadLink: true`.

### Notes & limits

- Some destinations answer with a verification page instead of the real landing page, especially large retailers. The actor reports the address it reached and the status it got, rather than pretending it arrived — switch on a residential proxy in the Proxy section if you need the real page.
- A few shorteners occasionally show a preview page instead of forwarding. The actor retries with a different browser identity and, failing that, reads the destination link off the preview page; if it still cannot resolve it, the record carries a `_warning` so you know the destination is unconfirmed.
- Destinations can differ by country and by device. Set the proxy country and the browser identity to match the audience you are auditing.
- Links that bounce through a page requiring a full browser (a click-to-continue button) end on that page — that is reported honestly as the last stop reached.
- This actor only inspects public link infrastructure. It collects no personal data.

# Actor input Schema

## `startUrls` (type: `array`):

Short links, affiliate links, ad links or any URL you want followed to its real destination. One record is returned per link, containing every hop of the chain.

## `maxHops` (type: `integer`):

How many redirects to follow before stopping. Chains longer than this end with stopReason = 'max_hops'. Most real links resolve in 1-5 hops.

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

How long to wait for each single hop to respond before giving up on it. The hop is still recorded, with stopReason = 'timeout'.

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

The browser the links are opened as. Some links send different destinations to desktop, mobile or bots, so changing this can change the result. Leave blank to use the built-in desktop Chrome identity.

## `followMetaRefresh` (type: `boolean`):

Follow redirects that are hidden inside the page itself as an automatic refresh instead of a normal redirect. Very common in link cloaking. Recommended: on.

## `followJsRedirects` (type: `boolean`):

Follow simple in-page script redirects that send the visitor onward without a normal redirect. Also common in link cloaking. Recommended: on.

## `maxItems` (type: `integer`):

Safety cap on how many links are traced in one run. Extra links beyond this number are skipped.

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

How many links are followed at the same time. Keep it low to look like normal traffic to the link providers.

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

Optional. Datacenter proxy is enough for most links. Some merchants send visitors to different pages depending on the country they appear to come from, so pick a residential proxy and country if you need a specific market's destination.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://amzn.to/3QZv1kM"
    },
    {
      "url": "https://s.click.aliexpress.com/e/_DdJcHZv"
    },
    {
      "url": "https://bit.ly/3xyzabc"
    }
  ],
  "maxHops": 15,
  "timeoutSeconds": 20,
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
  "followMetaRefresh": true,
  "followJsRedirects": true,
  "maxItems": 100,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `startUrl` (type: `string`):

Link to the start.

## `finalUrl` (type: `string`):

Link to the final.

## `finalStatus` (type: `string`):

Final Status.

## `merchantDomain` (type: `string`):

Merchant Domain as reported by the source.

## `affiliateNetwork` (type: `string`):

Affiliate Network as reported by the source.

## `totalHops` (type: `string`):

Total Hops.

## `stopReason` (type: `string`):

Stop Reason as reported by the source.

## `isCloaked` (type: `string`):

Is Cloaked. Boolean value.

## `isDeadLink` (type: `string`):

Is Dead Link. Boolean value.

## `_scrapedAt` (type: `string`):

UTC timestamp of the scrape, ISO 8601.

## `startHost` (type: `string`):

Start Host as reported by the source.

## `startDomain` (type: `string`):

Start Domain as reported by the source.

## `finalHost` (type: `string`):

Final Host as reported by the source.

## `finalPageTitle` (type: `string`):

Final Page Title as reported by the source.

## `redirectCount` (type: `string`):

Redirect Count. Whole number.

## `affiliateNetworkEvidence` (type: `string`):

Affiliate Network Evidence as reported by the source.

## `affiliateIds` (type: `string`):

Affiliate Ids.

## `affiliateIdSources` (type: `string`):

Affiliate Id Sources.

## `trackerDomains` (type: `string`):

Tracker Domains.

## `cloakingSignals` (type: `string`):

Cloaking Signals.

## `redirectTypes` (type: `string`):

Redirect Types.

## `totalElapsedMs` (type: `string`):

Total Elapsed Ms.

## `hops` (type: `string`):

Hops.

## `hopIndex` (type: `string`):

Hop Index as reported by the source.

## `method` (type: `string`):

Method as reported by the source.

## `statusCode` (type: `string`):

Status Code as reported by the source.

## `redirectType` (type: `string`):

Redirect Type as reported by the source.

## `elapsedMs` (type: `string`):

Elapsed Ms.

## `cookiesSet` (type: `string`):

Cookies Set as reported by the source.

## `trackingParams` (type: `string`):

Tracking Params.

## `browserProfile` (type: `string`):

Browser Profile as reported by the source.

## `pageTitle` (type: `string`):

Page Title as reported by the source.

# 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 = {
    "startUrls": [
        {
            "url": "https://amzn.to/3QZv1kM"
        },
        {
            "url": "https://s.click.aliexpress.com/e/_DdJcHZv"
        },
        {
            "url": "https://bit.ly/3xyzabc"
        }
    ],
    "maxHops": 15,
    "timeoutSeconds": 20,
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("xtracto/affiliate-redirect-tracer").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 = {
    "startUrls": [
        { "url": "https://amzn.to/3QZv1kM" },
        { "url": "https://s.click.aliexpress.com/e/_DdJcHZv" },
        { "url": "https://bit.ly/3xyzabc" },
    ],
    "maxHops": 15,
    "timeoutSeconds": 20,
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("xtracto/affiliate-redirect-tracer").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 '{
  "startUrls": [
    {
      "url": "https://amzn.to/3QZv1kM"
    },
    {
      "url": "https://s.click.aliexpress.com/e/_DdJcHZv"
    },
    {
      "url": "https://bit.ly/3xyzabc"
    }
  ],
  "maxHops": 15,
  "timeoutSeconds": 20,
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
  "maxItems": 100
}' |
apify call xtracto/affiliate-redirect-tracer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,xtracto/affiliate-redirect-tracer"
        }
    }
}
```

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/W5VWXny9YVMMwfdHb/builds/1FHQ2v8QjhZuy1yLN/openapi.json
