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

Extract bio, profile picture, verification badge, social media links, and all links from any public Linktree profile. Fast and affordable — paste usernames, click Start, and export results to JSON, CSV, or Excel

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

## Pricing

from $1.20 / 1,000 profile scrapeds

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/platform/actors/running/actors-in-store#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

## Linktree Profile Scraper

Extract everything public from any Linktree profile — bio, profile picture, verification badge, social media links, and every link on the page — and download it as clean JSON, CSV, or Excel. Just paste usernames or profile URLs and click **Start**. No coding required.

Whether you need a **Linktree scraper** for lead generation, influencer research, or brand monitoring, or a fast and affordable **Linktree API alternative**, this actor turns any list of linktr.ee profiles into structured, spreadsheet-ready data in seconds.

### What data does Linktree Profile Scraper extract?

For every public Linktree profile, you get:

- 👤 **Profile info** — username, display title, bio/description, and profile picture URL
- ✅ **Verification status** — whether the profile carries Linktree's verified badge
- 🗓️ **Account details** — Linktree account ID and account creation date
- 🔗 **Social links** — every connected social profile (Instagram, TikTok, YouTube, X, Facebook, Spotify, Twitch, and more) with its URL
- 📎 **All links** — every link on the page with title, URL, thumbnail, description, position, and lock status
- 🗂️ **Link groups** — grouped/folder links are preserved with their nested children, exactly as they appear on the page
- 📌 **Pinned links** — links pinned to the top of the profile

### Why scrape Linktree?

Linktree is the most popular link-in-bio platform, used by millions of creators, influencers, artists, and brands. Their public profiles are goldmines of structured data:

- 🔍 **Influencer & creator discovery** — see where creators send their audience: shops, merch, sponsorships, and other socials
- 📇 **Lead generation** — collect business websites, contact links, and social profiles at scale
- 📊 **Competitor & brand monitoring** — track which campaigns, products, and links brands promote, and how they change over time
- 🧭 **Market research** — analyze the link-in-bio ecosystem across niches, platforms, and verticals
- 🔗 **Data enrichment** — turn a plain list of Linktree usernames into full social graphs for your CRM or database

### How to scrape Linktree in 3 steps

1. **Add profiles** — paste Linktree usernames (`selenagomez`) or full URLs (`https://linktr.ee/selenagomez`) into the input. You can mix formats and add as many as you like.
2. **Click Start** — results usually arrive in well under a second per profile.
3. **Download your data** — export results as JSON, CSV, Excel, XML, or RSS, or pull them programmatically via the Apify API.

### Input

The actor accepts a single required field:

| Field | Type | Description |
|---|---|---|
| `profiles` | array of strings | Linktree usernames or full profile URLs. Formats can be mixed freely. |

Usernames, `@usernames`, and full URLs all work, in any mix. Duplicates are removed automatically before scraping, and the match is based on the profile itself — not on how you typed it. All of these count as one profile:

```
marjem
@marjem
linktr.ee/marjem
https://www.linktr.ee/marjem/
https://linktr.ee/marjem?utm_source=linktree&utm_medium=profiles-directory
```

That last form matters: links copied from Linktree's own profiles directory carry tracking parameters. They are still recognised as the same profile, so pasting a directory link next to a plain username never doubles your bill.

**Example input:**

```json
{
    "profiles": [
        "esportsworldcup",
        "https://linktr.ee/selenagomez"
    ]
}
```

### Output

The actor stores one dataset item per profile. Here's what each field means:

| Field | Description |
|---|---|
| `username` | Linktree username |
| `profileUrl` | Full URL of the profile page |
| `pageTitle` | Display title shown on the page |
| `description` | Bio / profile description |
| `profilePictureUrl` | Direct URL of the profile picture |
| `isVerified` | `true` if the profile has Linktree's verified badge |
| `accountId` | Linktree's internal account ID |
| `accountCreatedAt` | Account creation date as a Unix timestamp in milliseconds |
| `socialLinks` | Connected social profiles: array of `{ type, url, position }` |
| `links` | All links on the page: array of `{ id, title, url, type, thumbnail, position, description, locked, children }` |
| `pinnedLinks` | Pinned links, in the same structure as `links` |
| `scrapedAt` | Timestamp of when the profile was scraped (ISO 8601) |

Grouped links (folders) keep their nested items in `children`, so the output mirrors the page layout.

Linktree serves at most **1,000 links** per profile page, so that is the ceiling for the `links` field. Virtually every profile sits far below it — but if one does return exactly 1,000, the run log flags it so you know the profile may hold more.

**Example output (shortened):**

```json
{
    "username": "esportsworldcup",
    "profileUrl": "https://linktr.ee/esportsworldcup",
    "pageTitle": "@ewc",
    "description": "Esports World Cup. A new chapter in esports history 🏆",
    "profilePictureUrl": "https://ugc.production.linktr.ee/051014ae-eac5-470d-8d78-283df1a58004_0226-EWC-Social-Branding-Avatar-1080x1080-FR.png",
    "isVerified": true,
    "accountId": 75599522,
    "accountCreatedAt": 1712756739000,
    "socialLinks": [
        { "type": "INSTAGRAM", "url": "https://instagram.com/ewc_en", "position": 1 },
        { "type": "TIKTOK", "url": "https://tiktok.com/@ewc_en", "position": 4 },
        { "type": "YOUTUBE", "url": "https://youtube.com/@ewc", "position": 3 }
    ],
    "links": [
        {
            "id": "577179644",
            "title": "EWC Play Go Beyond Spectating",
            "url": "https://esportsworldcup.com/play",
            "type": "CLASSIC",
            "thumbnail": "https://assets.production.linktr.ee/tabler-icons/outline/vs.svg",
            "position": 0,
            "description": "The Esports World Cup experience doesn't stop at watching the action...",
            "locked": false,
            "children": []
        },
        {
            "id": "508428321",
            "title": "EWC AR",
            "url": null,
            "type": "GROUP",
            "thumbnail": null,
            "position": 9,
            "description": null,
            "locked": false,
            "children": [
                {
                    "id": "508429195",
                    "title": "EWC AR on X",
                    "url": "https://x.com/ewc_ar",
                    "type": "TWITTER_STATUS_LATEST",
                    "thumbnail": "https://assets.production.linktr.ee/tabler-icons/outline/brand-x.svg",
                    "position": 1,
                    "description": null,
                    "locked": false,
                    "children": []
                }
            ]
        }
    ],
    "pinnedLinks": [],
    "scrapedAt": "2026-08-06T04:39:11.761Z"
}
```

#### When a profile can't be scraped

If a profile can't be retrieved — because the account was deleted, the username is misspelled, or the entry isn't a readable profile at all — the run continues and the rest of your list is unaffected.

Skipped profiles are kept **out of your results** and listed separately under **Skipped profiles** on the run's Output tab, so your export stays clean and you are never billed for them. Each entry tells you what happened:

| Field | Description |
|---|---|
| `profileInput` | The exact value you supplied, so you can match it back to your source list |
| `profileUrl` | The profile URL the actor tried to open, or empty if the entry couldn't be read as a profile |
| `error` | A short, human-readable reason, such as `Profile not found` |
| `scrapedAt` | When the attempt was made (ISO 8601) |

If every profile in a run is skipped, the run is marked as **failed** rather than finishing silently with an empty result.

### Pricing

This actor is billed **per result** — you pay a flat, predictable price for each profile returned, with no separate platform usage charges to estimate. 1,000 profiles costs exactly 1,000 × the listed price, whether the run takes one minute or ten.

You only pay for profiles you actually receive:

- **Duplicates are free** — repeated inputs are collapsed before scraping, however they were written, including links that carry tracking parameters.
- **Skipped profiles are free** — deleted accounts, typos, and unreadable entries are reported separately and never billed.

### Speed and reliability

Linktree Profile Scraper is built to stay fast on large batches and to keep working when a site pushes back. Rate limiting is detected and handled automatically during the run, so you don't need to configure proxies, tune concurrency, or babysit long jobs. Add your list, start the run, and collect the results.

### Integrations and automation

Like every Apify actor, Linktree Profile Scraper plugs straight into your stack:

- **Schedule it** — re-scrape profiles daily or weekly with Apify Schedules and track how links and bios change over time
- **Call it via API** — trigger runs and fetch results from your own code with the Apify API (JavaScript and Python clients available)
- **Connect your tools** — pipe results into Zapier, Make, Google Sheets, Slack, or any other Apify integration
- **Webhooks** — get notified the moment a run finishes
- **Use it with AI agents** — the actor exposes a full input and output schema, so agents can call it and consume its results through the Apify MCP server

### FAQ

#### Do I need to configure proxies or any other settings?

No. The only thing you provide is the list of profiles. Everything else is handled for you during the run.

#### How many profiles can I scrape in one run?

There's no hard limit — add as many usernames or URLs as you need. A failure on one profile (for example, a deleted account) never stops the rest of the batch.

#### Can it scrape private or paywalled content?

No. The actor only returns what any visitor can see on a public profile page. Links marked as locked are reported with `locked: true`, but their protected content is not unlocked or bypassed.

#### What happens if a profile doesn't exist?

The run doesn't crash or stop. The profile is listed under **Skipped profiles** with the reason, and it isn't billed. Your main results stay clean and the run continues.

#### Am I charged for profiles that fail?

No. You are billed only for profiles actually returned in your results. Deleted accounts, misspelled usernames, and duplicate entries cost you nothing.

#### Is there a limit on how many links one profile returns?

Yes — 1,000 links per profile. That is Linktree's own page limit, not a restriction added here. Almost no profile comes close. If one does hit the number exactly, the run log says so.

#### Can I get results in a spreadsheet?

Yes. Every run can be exported to CSV, Excel, JSON, XML, or RSS directly from the Apify Console, or fetched in any of those formats via the API.

#### Is it legal to scrape Linktree?

This actor only extracts publicly available data from public profile pages — no login is required and no access controls are bypassed. Scraping public data is generally considered legal, but how you store and use the data may still be subject to privacy regulations such as GDPR or CCPA, as well as Linktree's terms of service. When in doubt, consult a legal professional.

### Feedback and support

Found a bug, a missing data field, or have a feature request? Open an issue in the actor's **Issues** tab in Apify Console — it's actively monitored.

### Disclaimer

This actor is not affiliated with, endorsed by, or sponsored by Linktree. All trademarks are the property of their respective owners. You are responsible for complying with applicable laws and Linktree's terms when using the extracted data.

# Actor input Schema

## `profiles` (type: `array`):

Linktree usernames (e.g. "esportsworldcup") or full URLs (e.g. "https://linktr.ee/esportsworldcup").

## Actor input object example

```json
{
  "profiles": [
    "https://linktr.ee/esportsworldcup",
    "marjem",
    "https://linktr.ee/johnnyrockets.me?utm_source=linktree&utm_medium=profiles-directory&utm_content=category-food-beverage",
    "@uanimals"
  ]
}
```

# Actor output Schema

## `profiles` (type: `string`):

One item per successfully scraped profile.

## `skipped` (type: `string`):

Profiles that could not be scraped, with the reason for each. Not billed.

# 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 = {
    "profiles": [
        "https://linktr.ee/esportsworldcup",
        "marjem",
        "https://linktr.ee/johnnyrockets.me?utm_source=linktree&utm_medium=profiles-directory&utm_content=category-food-beverage",
        "@uanimals"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("hgservices/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 = { "profiles": [
        "https://linktr.ee/esportsworldcup",
        "marjem",
        "https://linktr.ee/johnnyrockets.me?utm_source=linktree&utm_medium=profiles-directory&utm_content=category-food-beverage",
        "@uanimals",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("hgservices/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 '{
  "profiles": [
    "https://linktr.ee/esportsworldcup",
    "marjem",
    "https://linktr.ee/johnnyrockets.me?utm_source=linktree&utm_medium=profiles-directory&utm_content=category-food-beverage",
    "@uanimals"
  ]
}' |
apify call hgservices/linktree-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hgservices/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/WKwmOjCnDCTQjZEwO/builds/V9kmT9JqjoZmCwk27/openapi.json
