# Instagram Threads Facebook Brand Presence Mapper (`mambalabs/meta-brand-presence-mapper`) Actor

Resolves a company domain to its Instagram, Threads and Facebook accounts and returns follower and post counts from the public Open Graph cards. Threads is derived free from the Instagram handle. Flat, Clay ready, one row per company.

- **URL**: https://apify.com/mambalabs/meta-brand-presence-mapper.md
- **Developed by:** [Mamba Labs](https://apify.com/mambalabs) (community)
- **Categories:** Lead generation, Automation, Social media
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 company checkeds

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

### 🔎 What can Instagram Threads Facebook Brand Presence Mapper do?

Give it a company domain and it returns that company's **Instagram, Threads and Facebook** presence in one flat row: profile URLs, handles, follower counts and post counts.

### 💡 Why use Instagram Threads Facebook Brand Presence Mapper?

**Threads costs you nothing extra here, and that is a measurement rather than a claim.** Threads handles are Instagram handles: 5 of 5 measured across stripe, figma, supabase, shopify and hubspot. And 0 of 14 B2B homepages declare a Threads link at all. So a standalone Threads tool has nothing to read and has to pay a web search to rediscover a handle this actor already holds. Once Instagram resolves, Threads is one string substitution.

**It tells you which numbers are rounded.** Instagram renders "3M". Threads renders "306.9K". Those are the platforms rounding, not us. Both the expanded integer and the platform's own string are on the row, plus a flag, so you know before you sum a column.

**It tells you when Facebook refused.** Meta serves a login wall to anonymous clients on Pages. This actor reports `blocked`, which means unknown. It does not report zero.

#### 🧭 One user agent decision carries all three

Meta serves its own link preview crawler an Open Graph card and serves an anonymous browser a JavaScript shell with the counts stripped out. Measured on the same URLs on the same day: Instagram returns 718,863 bytes with "3M Followers, 1,832 Following, 3,707 Posts" to the crawler, and 612,000 bytes of empty shell to a browser.

So all three platforms are read from the card Meta publishes for previews. No login, no API key, no browser automation.

### 📋 What data can Instagram Threads Facebook Brand Presence Mapper extract?

| Field | Type | Meaning |
|---|---|---|
| `degraded` | boolean | True when this row could not be produced normally, for example the company site was unreachable and no discovery could run. A degraded row is never charged. |
| `degradation_reason` | string | null | Why the row is degraded, in plain words. Null on a normal row. |
| `company_domain` | string | null | The company domain this row is about, normalized. Null when only a handle or a name was supplied. This is the join key across the whole Mamba Labs fleet. |
| `company_name` | string | null | The company name as supplied or derived. Improves search accuracy and is what the identity gate matches against. |
| `platforms_checked` | integer | null | How many of the three Meta surfaces were requested and attempted on this row. |
| `platforms_found` | integer | null | How many of those resolved to a trustworthy account. |
| `instagram_url` | string | null | Canonical Instagram profile URL, or null when none was found. |
| `instagram_handle` | string | null | The resolved Instagram handle. This is also the Threads handle: 5 of 5 measured. |
| `instagram_followers` | integer | null | Follower count expanded from what Instagram renders. Instagram serves "3M", not the integer, so read instagram\_followers\_exact before summing. |
| `instagram_followers_display` | string | null | Exactly what Instagram rendered, for example "3M". Kept alongside the expanded number so you can always see what the platform actually said. |
| `instagram_followers_exact` | boolean | null | False whenever a K, M or B suffix was expanded, because the suffix is the rounding. True only when Instagram served every digit. |
| `instagram_following` | integer | null | How many accounts this account follows. |
| `instagram_posts` | integer | null | Post count on the account. Zero is a real answer and means a registered but unused account. |
| `instagram_discovery` | string | null | How the account was found: input\_handle, homepage\_sameas, homepage\_link, search or pattern\_guess. |
| `instagram_status` | string | ok, not\_found, not\_extractable, blocked, identity\_mismatch, auth\_failed or skipped. |
| `threads_url` | string | null | Canonical Threads profile URL. Derived from the Instagram handle at no extra discovery cost. |
| `threads_handle` | string | null | The Threads handle, which is the Instagram handle. Null when Instagram did not resolve, because a Threads guess with no Instagram behind it has no evidence at all. |
| `threads_followers` | integer | null | Follower count expanded from what Threads renders, for example "306.9K". Read threads\_followers\_exact before summing. |
| `threads_followers_display` | string | null | Exactly what Threads rendered, for example "306.9K". |
| `threads_followers_exact` | boolean | null | False whenever a suffix was expanded. True only when Threads served every digit. |
| `threads_posts` | integer | null | Number of threads posted on the account. |
| `threads_status` | string | ok, not\_found, not\_extractable, blocked, identity\_mismatch, auth\_failed or skipped. not\_found here usually means the company has an Instagram account and never opened Threads, which is a real and common answer. |
| `facebook_url` | string | null | Canonical Facebook Page URL, or null when none was found. The URL is far more reliable than the count on this platform. |
| `facebook_handle` | string | null | The Page handle or vanity path. |
| `facebook_followers` | integer | null | Follower count where Meta served one. Frequently null: Meta serves a login interstitial to anonymous clients and blocks aggressively. Read facebook\_status first. |
| `facebook_followers_display` | string | null | Exactly what Facebook rendered, where it rendered anything. |
| `facebook_followers_exact` | boolean | null | False whenever a suffix was expanded. True only when Facebook served every digit. |
| `facebook_likes` | integer | null | Page likes where served. Distinct from followers on a modern Page. |
| `facebook_discovery` | string | null | How the Page was found: input\_handle, homepage\_sameas, homepage\_link, search or pattern\_guess. |
| `facebook_status` | string | ok, not\_found, not\_extractable, blocked, identity\_mismatch, auth\_failed or skipped. blocked is the NORMAL answer here rather than an incident: Meta refuses anonymous clients on Pages most of the time. |
| `run_date` | string | ISO 8601 timestamp of this run. Social counts move, so a row without a date is a number with no shelf life. |

`threads_handle` is null whenever Instagram did not resolve. That is deliberate: the 5 of 5 evidence is about Instagram handles, and a Threads guess with no Instagram behind it would carry none of it.

### 🛠️ How to map a company's Meta presence

1. Put a company domain in `company_domain`.
2. Use `platforms` to pick which of the three you want. Dropping `facebook` is the common choice and it makes the run cheaper and faster.
3. If you already know the Instagram handle, put it in `handle`. That skips Instagram discovery **and** gives Threads its handle for free.
4. For a list, pass an array of objects.

#### 🧪 Using it in Clay

Add an **Enrichment > Apify** column, pick this actor, map `company_domain`. All three platforms arrive as flat columns on one row, so you get Instagram, Threads and Facebook from a single credit rather than three.

For consumer brand qualification, `instagram_followers` plus `threads_posts` is a useful pair: a large Instagram account with zero Threads posts is a brand that has not moved yet.

### 💵 How much does it cost?

Pay per event. You are charged for output, never for input.

| Event | Fires when | Price |
|---|---|---|
| `company-checked` | Once per company for which the discovery cascade completed and a non degraded row was produced, whether or not any Meta platform resolved. Does not fire on a degraded row, because on a degraded row the company site was never read and no presence was measured. | $0.0050 |
| `platform-resolved` | Once per REQUESTED Meta platform whose candidate URL passed the identity gate. Fires on the validation work, not on a populated follower cell. A candidate dropped as an impersonator does not charge: the work was done and the answer is that there is no such profile. A platform the caller did not request never fires it. | $0.0030 |
| `follower-count-extracted` | Once per Meta platform where a numeric follower count was read off the public Open Graph card. Does not fire on not\_extractable, blocked, identity\_mismatch or a URL only run. Facebook therefore often does not fire it, which is correct: it is the platform we most often cannot read. | $0.0025 |

`platform-resolved` fires per platform you REQUESTED and resolved, so a run limited to `["instagram","threads"]` cannot bill you for Facebook.

A blocked Facebook fetch charges the resolution event, because the URL was found and validated, and does not charge the extraction event, because no number was returned.

**What the same coverage costs bought a la carte:** Bought separately at Store list prices: apify/instagram-profile-scraper $0.0026, apify/threads-profile-api-scraper $0.0050, apify/facebook-pages-scraper $0.0120, so $0.0196 for the three. Every one of them requires the handle or the page URL as input. This actor resolves all three from a domain, and it derives the Threads handle from the Instagram one for nothing, which is a step none of those three performs.

### ⌨️ Input

| Field | Type | Required | Meaning |
|---|---|---|---|
| `company_domain` | string | no | Bare company domain, for example shopify.com. Supply this or a handle. With a domain the actor runs full discovery; with a handle it skips straight to the fetch. |
| `company_name` | string | no | Optional. Improves search accuracy and is what the identity gate checks a discovered profile against, so supplying it reduces wrong matches. |
| `handle` | string | no | Optional. The Instagram handle with or without the leading @. Supplying it skips Instagram discovery AND gives Threads its handle for free, because Threads handles are Instagram handles (5 of 5 measured). |
| `platforms` | array | no | Which of the three Meta surfaces to map. Default is all three. Dropping Facebook is the common choice: it is the least reliable of the three and it costs a fetch to find that out. |
| `includeFollowerCounts` | string | no | When "true" (default) the profile page is fetched and the counts are extracted. Set "false" to resolve the profile URL only, which is cheaper and needs no proxy. Sent as a string for Clay compatibility. |
| `skipCache` | string | no | When "false" (default) a successful lookup is cached for seven days and reused. Set "true" to force a fresh fetch. Sent as a string for Clay compatibility. |

```json
{
  "company_domain": "shopify.com",
  "company_name": "Shopify",
  "platforms": [
    "instagram",
    "threads",
    "facebook"
  ]
}
```

### 📤 Output

One flat, snake\_case row per company. No nested objects, so it drops straight
into Clay, a spreadsheet or a warehouse table without a flattening step.

```json
{
  "degraded": false,
  "degradation_reason": null,
  "company_domain": "shopify.com",
  "company_name": "Shopify",
  "platforms_checked": 3,
  "platforms_found": 2,
  "instagram_url": "https://www.instagram.com/shopify/",
  "instagram_handle": "shopify",
  "instagram_followers": 3000000,
  "instagram_followers_display": "3M",
  "instagram_followers_exact": false,
  "instagram_following": 1832,
  "instagram_posts": 3707,
  "instagram_discovery": "homepage_link",
  "instagram_status": "ok",
  "threads_url": "https://www.threads.com/@shopify",
  "threads_handle": "shopify",
  "threads_followers": 306900,
  "threads_followers_display": "306.9K",
  "threads_followers_exact": false,
  "threads_posts": 153,
  "threads_status": "ok",
  "facebook_url": "https://www.facebook.com/shopify",
  "facebook_handle": "shopify",
  "facebook_followers": null,
  "facebook_followers_display": null,
  "facebook_followers_exact": null,
  "facebook_likes": null,
  "facebook_discovery": "homepage_link",
  "facebook_status": "blocked",
  "run_date": "2026-08-22T09:00:00.000Z"
}
```

#### false versus null, and why the difference matters

`false` means we looked and the answer is no. `null` means we could not look,
or the platform withheld it. They are never interchangeable in this output. If
you filter for companies with no presence on this platform, filter on `false`,
because `null` rows are unknown rather than absent and including them will
overstate your list.

### 💡 Tips

- **Drop Facebook unless you need it.** It is the least reliable of the three and it costs a fetch to discover that.
- **Read the `_display` columns.** "3M" tells you more about the precision of the number than 3000000 does.
- **A big Instagram with no Threads is a signal**, not a gap. It usually means the brand has not adopted the newer network.
- **Supply the Instagram handle when you have it.** It pays for itself twice, once on Instagram and once on Threads.

### ⚠️ Known limits

- **Instagram, Threads and Facebook all round their counts.** There is no exact figure on the card for a large account. The `_exact` flags mark every row where that applies.
- **Facebook is best effort and frequently blocked.** Meta serves a 427 KB login interstitial to anonymous clients and blocks aggressively. This is a known, measured, carried across ceiling: a previous Mamba Labs actor recorded 590 upstream failures on this exact path and makes one bounded attempt because retry does not recover. Expect `blocked`, and read the URL, which is reliable.
- **No posts, comments, reels, stories or engagement.** Account level presence and counts only.
- **A private Instagram account still returns a card** with counts, but no content. That is Instagram's behavior, not ours.
- **Follower counts are a public vanity metric,** a proxy for reach rather than a measurement of it.

### ❓ FAQ

**Why is Facebook so often blocked when Instagram works?**
Meta treats Pages differently from Instagram profiles for anonymous clients. Pages get a login interstitial. This is Meta's choice and no logged out tool gets around it reliably.

**How can Threads be free?**
Because its handle is the Instagram handle, measured 5 of 5. Once Instagram resolves there is no discovery left to do, only one fetch.

**Why are Instagram counts rounded?**
Instagram renders "3M" on the card. The exact number is not on the wire. `instagram_followers_display` shows you exactly what the platform said.

**Can I get just Instagram?**
Yes. Set `platforms` to `["instagram"]`. You are then billed for one platform, not three.

**Does this need a login or an API key?**
No.

### 🧩 Want other GTM data?

Mamba Labs builds a fleet of GTM enrichment actors that share one flat,
Clay-ready output convention, so their rows join on `company_domain` with no
cleaning step:

- **Company Firmographic Enricher** headcount, industry, location and revenue band from a domain, joins on `company_domain`.
- **Domain to LinkedIn URL Resolver** the company LinkedIn URL for domains where the social mapper found none.
- **GTM Hiring Signal Scraper** open go to market roles, which is the buying signal a follower count is a proxy for.
- **Company Social Presence Mapper** every platform in one row when you want breadth rather than depth on one network.

Full fleet: [apify.com/mambalabs](https://apify.com/mambalabs)

### 🆘 Support

Issues, field requests and bug reports: open an issue on the actor's Issues tab.
Mamba Labs reads every one.

# Actor input Schema

## `company_domain` (type: `string`):

Bare company domain, for example shopify.com. Supply this or a handle. With a domain the actor runs full discovery; with a handle it skips straight to the fetch.

## `company_name` (type: `string`):

Optional. Improves search accuracy and is what the identity gate checks a discovered profile against, so supplying it reduces wrong matches.

## `handle` (type: `string`):

Optional. The Instagram handle with or without the leading @. Supplying it skips Instagram discovery AND gives Threads its handle for free, because Threads handles are Instagram handles (5 of 5 measured).

## `platforms` (type: `array`):

Which of the three Meta surfaces to map. Default is all three. Dropping Facebook is the common choice: it is the least reliable of the three and it costs a fetch to find that out.

## `includeFollowerCounts` (type: `string`):

When "true" (default) the profile page is fetched and the counts are extracted. Set "false" to resolve the profile URL only, which is cheaper and needs no proxy. Sent as a string for Clay compatibility.

## `skipCache` (type: `string`):

When "false" (default) a successful lookup is cached for seven days and reused. Set "true" to force a fresh fetch. Sent as a string for Clay compatibility.

## `source_tag` (type: `string`):

Internal attribution tag set by Mamba Labs on published task examples. Not required, and nothing depends on it. Leave it empty.

## Actor input object example

```json
{
  "company_domain": "shopify.com",
  "company_name": "Shopify",
  "platforms": [
    "instagram",
    "threads",
    "facebook"
  ],
  "includeFollowerCounts": "true",
  "skipCache": "false"
}
```

# Actor output Schema

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

Dataset of one flat row per company, with per platform status so a blocked fetch never reads as a zero.

# 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 = {
    "company_domain": "shopify.com",
    "company_name": "Shopify",
    "handle": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("mambalabs/meta-brand-presence-mapper").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 = {
    "company_domain": "shopify.com",
    "company_name": "Shopify",
    "handle": "",
}

# Run the Actor and wait for it to finish
run = client.actor("mambalabs/meta-brand-presence-mapper").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 '{
  "company_domain": "shopify.com",
  "company_name": "Shopify",
  "handle": ""
}' |
apify call mambalabs/meta-brand-presence-mapper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mambalabs/meta-brand-presence-mapper"
        }
    }
}

```

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/HXh65I0JBjPsunbY8/builds/7gMh0W3zeagsFF1tf/openapi.json
