# Linktree Profile Scraper (`axiomworks/linktree-profile-scraper`) Actor

Scrape public Linktree profiles and return one row per profile with usernames, names, bios, verification, avatars, social links, destination links, emails, and link counts. Links inside groups are flattened into the profile’s links array; profiles with no visible links may still be returned.

- **URL**: https://apify.com/axiomworks/linktree-profile-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.48 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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

## Linktree Profile Scraper

**Returns:** one row per public Linktree profile with username, name, bio, verified status, social links, destination links, link count, emails, phones, and external domains.
**Input:** `{"usernames":["MrBeast"],"maxItems":1}`
**Best for:** creator research, social account discovery, and monitoring links on public profile pages.

```json
{"id":"e59389a3-1311-4f1c-befb-69eb623a5b28","sourceUrl":"https://linktr.ee/MrBeast","username":"MrBeast","name":"MrBeast","verified":true,"linkCount":15}
```

### What does Linktree Profile Scraper do?

Linktree Profile Scraper reads public link-in-bio profile pages on linktr.ee and returns one structured row for each profile it finds. It takes usernames, full profile URLs, or both. The Actor extracts information embedded in the public page, including profile identity, a description, verification status, the avatar URL, social links, and the page's destination links. It also computes a link count and derives email addresses and social handles when those values are visible in the public page data. No login is required.

A Linktree profile can contain many links, social icons, and link groups. This Actor keeps those together in one profile row so a run with ten profiles can produce up to ten rows. The `links` array includes child links from groups. The `socialLinks` array is separate from ordinary destination links because Linktree represents it separately in the public page data. Empty arrays mean the public profile did not expose values in that category at the time of collection.

The Linktree scraper visits each profile page sequentially. It waits between requests and retries temporary blocking responses with a new proxy session. A missing username is logged and skipped. Each result includes the URL of the page used to create it and a stable account identifier. The output is suitable for repeat collection because those two fields let you compare results between runs.

This Actor is an independent tool and is not affiliated with Linktree. Public pages can change, disappear, or restrict visible links. The Actor reports what it can find in the page response during the run; it does not obtain private profile information or data behind a login.

### What data can you get?

The dataset has one row for each public profile successfully read. Fields can be null or empty when a profile does not expose the corresponding information. In particular, a profile may show no ordinary links or no social links. The presence of a profile row does not imply every optional field is filled.

| Field | Type | Meaning |
| --- | --- | --- |
| `id` | string | Stable Linktree account identifier used to deduplicate a run. |
| `sourceUrl` | string | Profile page URL requested for the row. |
| `username` | string | Username shown in the public page data. |
| `name` | string | Public display name or page title. |
| `bio` | string or null | Public profile description, when present. |
| `verified` | boolean or null | Public verification flag supplied by the page. |
| `avatarUrl` | string or null | Public avatar image URL, when supplied. |
| `createdAt` | string or null | Account creation time normalized to an ISO date. |
| `socialLinks` | array | Public social icons as objects with `type` and `url`. |
| `links` | array | Visible destination links, including links inside groups, with title, URL, type, and thumbnail. |
| `linkCount` | integer | Count of entries in the flattened `links` array. |
| `emails` | array | Addresses found in the bio or `mailto:` destination links. |
| `phones` | array | Phone numbers from `tel:` links, WhatsApp links, and international numbers written in the bio. |
| `externalDomains` | array | Distinct non-social website domains the profile links to, useful for finding a creator's own sites and stores. |
| `socialHandles` | object | Platform-to-handle map derived from public social and destination URLs. |
| `category` | string or null | Optional AI classification: creator, musician, business, brand, or other. |

A link URL is recorded as it appears in the profile data. The Actor does not visit each destination website, verify that a destination still works, or replace tracking and short URLs with their final destinations. This distinction matters when a profile uses a redirect service. The `thumbnail` value may be null even when a destination link exists. The `socialHandles` map covers Instagram, TikTok, Facebook, X, YouTube, LinkedIn, Threads, Twitch, Snapchat, Pinterest, Telegram, GitHub, Spotify, Discord and WhatsApp, and is a convenience derived from URL paths, so check the original `socialLinks` and `links` arrays when exact account identity matters.

The `emails` field is deliberately narrow. It collects address strings from the public bio and explicit email links. It does not guess an owner's email address or query an account directory. Many public profiles have no email address, and an empty array is a normal result.

### How to use

Open the Actor's Input tab and enter one or more Linktree usernames, such as `MrBeast`. You may paste full `https://linktr.ee/...` profile URLs into the usernames field, or add them in the Start URLs field. Set Maximum profiles to the number of rows you want. Run the Actor, then open the Dataset tab to inspect or export the profile rows.

The input list is treated as a set of profiles: repeated usernames with different capitalization are collected once in a run. A run stops when it has pushed `maxItems` successful profile rows or exhausted the supplied list. If a supplied username is not found, it does not consume an output row. To get a specific number of rows, provide enough existing public profiles and set `maxItems` to the desired count.

For repeated monitoring, run the same input periodically and compare rows by `id`. The account identifier is a stronger comparison key than the display name, which an account owner can edit. Compare `linkCount` for a quick indication that the page changed, then inspect the `links` array to see which URLs or titles changed. Review `sourceUrl` alongside a changed record to confirm which profile was fetched.

The default proxy configuration uses US residential Apify Proxy sessions. A custom proxy configuration can be supplied through the Input tab. Requests are limited to about one page per second, and temporary blocks are retried with backoff. If a page remains inaccessible after the retry budget, it is skipped and a warning appears in the run log. A dead URL or a nonexistent username will not create a placeholder dataset item.

### Input

| Field | Required | Default | How it is used |
| --- | --- | --- | --- |
| `usernames` | One of `usernames` or `startUrls` | None | List of usernames or full linktr.ee profile URLs. |
| `startUrls` | One of `usernames` or `startUrls` | None | List of profile URL objects, each with a `url` property. |
| `maxItems` | No | `50` | Maximum successful profile rows to push, from 1 to 10,000. |
| `proxyConfiguration` | No | US residential Apify Proxy | Proxy settings used for page requests. |
| `enrich` | No | `true` | Ask Jev to classify owners when a TypeSafe key is configured. |
| `maxJevCalls` | No | `500` | Upper bound on Jev requests in one run. |

Here is an input for two profiles. The `maxItems` value means at most two profile rows are stored. You may omit `proxyConfiguration` to use the Actor's residential default. The `startUrls` alternative is useful when your workflow already stores full profile URLs.

```json
{
  "usernames": ["MrBeast", "selenagomez"],
  "maxItems": 2,
  "enrich": true
}
```

Only the linktr.ee host is accepted for profile URLs. A malformed profile entry is ignored when other valid entries remain; a run with no valid targets fails with a clear input error. There is no search endpoint in this Actor. You supply the profile identifiers you want to collect.

### Output

The following abbreviated record is based on a local run against the public MrBeast profile. The full row includes the link and social-link arrays; the short version keeps the example readable. Values on live public pages can change between runs.

```json
{
  "id": "e59389a3-1311-4f1c-befb-69eb623a5b28",
  "sourceUrl": "https://linktr.ee/MrBeast",
  "username": "MrBeast",
  "name": "MrBeast",
  "verified": true,
  "createdAt": "2025-08-15T05:37:11.000Z",
  "linkCount": 15,
  "category": null
}
```

A full `links` entry has a title, a URL, a Linktree link type, and a thumbnail URL or null. A `socialLinks` entry has a social type and URL. The `linkCount` number is calculated from the flattened `links` array, so nested child links count as separate entries when they have URLs. Other arrays may legitimately be empty. Some profiles show an avatar or verification badge but expose no ordinary destination links.

The optional `category` value is produced by TypeSafe Jev, a third-party AI processor. When enrichment is enabled and the TypeSafe key is available at runtime, the Actor sends the public name, bio, and a bounded selection of link titles and URLs for classification. If the processor returns an error or is unavailable, the profile row still appears with `category: null`. Profile extraction itself does not depend on that classification.

For verification workflows, a hidden `__verifySnapshots` flag saves source snippets for the first ten emitted records to the run's key-value store under `SNAPSHOTS`. It is intended for checking where output values came from and is not needed for ordinary runs. Snapshot entries are keyed by the dataset record ID.

### How much does it cost?

This Actor is charged per result row pushed to the dataset. A successful AI classification can trigger an additional enriched-result event for that same row. The Actor does not charge a result event for a skipped, missing, or inaccessible profile. Open the Actor's Pricing tab for current event pricing and platform usage details.

Use `maxItems` to bound the number of result rows. The Actor stops when that count is reached, even if additional usernames remain in the input. If you want to check a small sample before collecting a larger list, set a small `maxItems` value and review the fields in the returned rows.

### Use with AI agents (MCP)

Apify's MCP server can expose this Actor as a tool to an AI agent. Configure the server with the Store path so the agent can discover its input description and output fields:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=axiomworks/linktree-profile-scraper"
    }
  }
}
```

Ask an agent to collect a known public profile and summarize its links, or to compare a list of public profiles. For example: “Get the public Linktree profile for MrBeast and list its social accounts,” or “Collect these three Linktree usernames and show each profile's `linkCount`.” The agent should provide usernames or URLs because the Actor does not discover profiles by keyword. Another useful prompt is: “Return the `sourceUrl`, `name`, and `emails` fields for these known profiles.” Empty email arrays should remain empty rather than being filled by inference.

The MCP tool's input schema places target fields first and describes how to use the limits. Agent callers can set `maxItems` to make a run predictable. The data remains a snapshot of the public pages at collection time, so the agent should include the source URL when presenting a result to a user.

### Integrations and API

You can send the same input through the Apify API, then read the run's dataset items. The examples below show the basic call shape. Replace the token placeholder with your own Apify token in your local environment. Keep credentials out of shared scripts, logs, and published repositories.

Python example:

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("axiomworks/linktree-profile-scraper").call(
    run_input={"usernames": ["MrBeast"], "maxItems": 1}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["sourceUrl"], item["name"], item["linkCount"])
```

JavaScript example:

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('axiomworks/linktree-profile-scraper').call({
  usernames: ['MrBeast'], maxItems: 1,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) process.stdout.write(`${item.sourceUrl} ${item.name}\n`);
```

cURL example:

```sh
curl -X POST "https://api.apify.com/v2/acts/axiomworks~linktree-profile-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"usernames":["MrBeast"],"maxItems":1}'
```

The resulting JSON rows can feed a spreadsheet, a monitoring workflow, or an internal data pipeline. Keep `id` and `sourceUrl` when storing them so later runs can be matched reliably. To compare links, preserve the `links` array rather than relying only on `linkCount`; different link sets may have the same count.

### FAQ

**Why did a username return no row?** The public page may not exist, may be temporarily blocked, or may not contain usable public profile data. Review the run log for the username and request status. A missing page is skipped, and the Actor does not push an error-shaped record.

**Will one profile produce one row per link?** No. Each successful profile produces one row. All visible destination links are nested in that row's `links` array, and `linkCount` gives the array length.

**Why is `category` null?** Classification requires a configured TypeSafe key and an available Jev response. If enrichment is disabled or a Jev request fails, `category` stays null and the profile row is still returned.

**Can `emails` or `socialHandles` be empty?** Yes. `emails` depends on explicit public text or email links. `socialHandles` depends on recognizable social-platform URLs. Empty collections are normal and should not be interpreted as missing data errors.

**Does the Actor open destination links?** No. It reads the Linktree profile page. Destination URLs are copied from that page and are not independently checked or followed.

**Can I pass the same username twice?** Yes, but it is deduplicated within the run by case-insensitive username. The output also carries a stable account `id` for cross-run matching.

### Is it legal to scrape Linktree?

Public profile pages can be accessed without logging in, but laws and site rules differ by location and use. Review your intended use and the applicable rules before processing or redistributing collected information. The Actor only reads public page responses and does not access private pages, sign in, or bypass a CAPTCHA. It records public URLs and text supplied by the profile owner at the time of collection.

If you use this data in outreach or an automated decision, verify that your workflow has an appropriate basis and respects the people involved. Public availability alone does not establish permission for every downstream use. This tool is not affiliated with Linktree, and its output should be attributed to the public source URL when presented elsewhere.

### Feedback

If a public profile produces an unexpected result, include the input username, the run identifier, the affected output field, and what the public profile displayed at the time. That context helps distinguish a changed page layout from a profile that intentionally leaves a field empty. Please avoid sending passwords, private account details, or API credentials in a report.

Feature requests are most useful when they describe a concrete output need, such as a link type that is visible on a public page but missing from the `links` array. For repeatability, note whether the page has groups, social icons, or a profile lock. The Actor's source URLs and stable IDs make it easier to locate and compare affected records.

# Actor input Schema

## `usernames` (type: `array`):

Linktree usernames or full profile URLs to extract; supply this or startUrls. Up to 10,000 profiles, with one result per public profile.

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

Public linktr.ee profile URLs to extract; use these when you already have full URLs.

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

Maximum result rows to return, 1-10000, default 50; the Actor stops after this many successful profiles.

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

Apify Proxy settings for profile requests; defaults to US residential sessions to reduce temporary blocking.

## `enrich` (type: `boolean`):

Classify each profile owner with a third-party AI processor when a TypeSafe key is configured; default true.

## `maxJevCalls` (type: `integer`):

Maximum TypeSafe Jev calls per run, 0-500, default 500; used for category and fallback extraction.

## Actor input object example

```json
{
  "usernames": [
    "selenagomez",
    "MrBeast",
    "therock"
  ],
  "startUrls": [
    {
      "url": "https://linktr.ee/MrBeast"
    }
  ],
  "maxItems": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "enrich": true,
  "maxJevCalls": 500
}
```

# Actor output Schema

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

Public Linktree profiles with links and social accounts

# 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 = {
    "usernames": [
        "selenagomez",
        "MrBeast",
        "therock"
    ],
    "startUrls": [
        {
            "url": "https://linktr.ee/MrBeast"
        }
    ],
    "maxItems": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/linktree-profile-scraper").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 = {
    "usernames": [
        "selenagomez",
        "MrBeast",
        "therock",
    ],
    "startUrls": [{ "url": "https://linktr.ee/MrBeast" }],
    "maxItems": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/linktree-profile-scraper").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 '{
  "usernames": [
    "selenagomez",
    "MrBeast",
    "therock"
  ],
  "startUrls": [
    {
      "url": "https://linktr.ee/MrBeast"
    }
  ],
  "maxItems": 3
}' |
apify call axiomworks/linktree-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/linktree-profile-scraper"
        }
    }
}
```

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/cKkjgQB3ue4gahnNd/builds/1YT0eMzCBlq2191o0/openapi.json
