# Instagram Merchant Profile & Bio-Link Extractor (`zucchini_gopher_m2v/instagram-merchant-profile-scraper`) Actor

Extract public Instagram business profiles: followers, engagement, business contact and address, and the bio links that are a merchant's real storefront (Shopee, Tokopedia, WhatsApp, webstore). For competitor mapping and lead generation. No login needed.

- **URL**: https://apify.com/zucchini\_gopher\_m2v/instagram-merchant-profile-scraper.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/zucchini_gopher_m2v) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.50 / 1,000 profiles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## Instagram Merchant Profile & Bio-Link Extractor

Extract public Instagram business profiles — followers, engagement, business
contact details, and the **bio links that are a merchant's actual
storefront** (Shopee, Tokopedia, WhatsApp, Linktree, own webstore).

For competitor mapping, seller research and lead generation.

No login, no API key. HTTP-only — no browser.

### ⚠️ This does not scrape an Instagram Shop

If you came here for Instagram Shop products or a product catalog: **that
data is no longer public.** Verified anonymously on 2026-09-01 —
`/<user>/shop/` and `/explore/shop/` redirect to the login page, five major
retail accounts carry zero shopping/catalog fields, and there is no product
tagging on posts (`product_type` is only ever `clips`/`igtv`, which is the
*media* type). Meta wound Instagram Shopping down.

No amount of scraping technique recovers data a platform stopped publishing,
so this actor extracts what genuinely is public — and for a merchant, the
bio link **is** the shop.

### Output

```json
{
  "username": "cottonink",
  "fullName": "COTTONINK | Jakarta",
  "biography": "Now Available:\nFall Collection 2026🍂 ...",
  "isVerified": true,
  "followers": 680168,
  "following": 150,
  "postCount": 7483,

  "bioLinks": [
    { "url": "http://linktr.ee/COTTONINK", "title": "Shop Now!",
      "linkType": "external", "platform": "LINK_AGGREGATOR" }
  ],
  "primaryShopLink": "http://linktr.ee/COTTONINK",
  "linkPlatforms": ["LINK_AGGREGATOR"],
  "marketplaces": [],
  "sellsOnMarketplace": false,
  "hasWhatsApp": false,

  "_source": "S2-profile-html"
}
```

With the API strategy you additionally get business contact and posts:

```json
{
  "isBusinessAccount": true,
  "businessContactMethod": "CALL",
  "businessCity": "Beaverton, Oregon",
  "businessLatitude": 45.5076448,
  "avgEngagementPerPost": 187959.7,
  "engagementRatePercent": 0.0645,
  "recentPosts": [
    { "shortcode": "DctPchKOVcw", "likes": 277530, "comments": 1935,
      "mediaType": "clips", "takenAt": "2026-08-31T13:56:44Z" }
  ]
}
```

Instagram's `l.instagram.com` redirect wrapper is unwrapped, so `bioLinks`
carry the real destination, deduplicated, each labelled with the platform a
merchant is actually selling on.

### Input

```json
{
  "usernames": ["cottonink", "@nike", "https://www.instagram.com/hijup/"],
  "includeRecentPosts": true,
  "delaySeconds": 2
}
```

| Field | Description |
| --- | --- |
| `usernames` | Handles or profile URLs; `@` and query strings are handled |
| `includeRecentPosts` | Attach recent posts and compute engagement rate |
| `maxPostsPerProfile` | Cap attached posts (Instagram returns ~12 anonymously) |
| `delaySeconds` | Pause between accounts — pacing keeps a run alive |
| `proxyConfiguration` | Residential **strongly recommended** |

### Read this before relying on the output

**Three strategies, and the richest one is the minority path.** The actor
tries the JSON API (S1), then the page's embedded JSON (S2), then `og` meta
tags (S3), and records which one produced each row in `_source`.

In a 3-account test run, **2 of 3 accounts fell through to S2**. That matters
because:

- `businessEmail`, `businessPhone`, `businessContactMethod`, the business
  address fields and `recentPosts` come from **S1 only**. On S2 rows they are
  empty — not because the merchant has none, but because that source doesn't
  carry them.
- S3 rows have **rounded** counts (`680000` rather than `680168`) and are
  tagged `_warning: counts_are_rounded_og_values`.

Filter on `_source` if you need guaranteed business contact data.

**Instagram throttles anonymous traffic hard**, and signals it with a 200
that redirects to a login wall rather than a clean 429. Profiles are
therefore fetched sequentially with a delay, and a block rotates both the TLS
fingerprint and the proxy session. Without a residential proxy expect login
walls after a handful of accounts.

### Known limits

- **No shop/product/catalog data** — see above.
- Business contact and posts only on S1 rows.
- `og` counts are rounded, and flagged when used.
- `engagementRatePercent` is computed over the ~12 fetched posts — a recent
  sample, not a lifetime average.
- Private accounts expose no posts; Instagram CDN media URLs are signed and
  expire, so download promptly if you need the images.

See [CRAWLING\_METHOD.md](CRAWLING_METHOD.md) for the full evidence on the
missing shop surface, the strategy comparison, and the rate-limit behaviour.

# Actor input Schema

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

Handles or profile URLs, e.g. \["cottonink", "@nike", "https://www.instagram.com/hijup/"]. Only public profiles can be read - private accounts return a NOT\_FOUND-style row.

## `includeRecentPosts` (type: `boolean`):

Attach the most recent posts with caption, likes, comments and media URLs, and compute an engagement rate from them. Posts come from the JSON API only - when the actor falls back to page HTML for an account, that account's posts will be empty.

## `maxPostsPerProfile` (type: `integer`):

Cap how many recent posts to attach. Instagram returns about 12 on the first page anonymously; asking for more does not fetch more.

## `delaySeconds` (type: `integer`):

Pause between accounts. Instagram throttles anonymous traffic per IP and starts serving login walls when hit too fast - pacing keeps a run alive far longer than speed does. Lower it only with a good residential proxy.

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

STRONGLY RECOMMENDED. Instagram rate-limits anonymous traffic hard; without a rotating residential proxy a run will start hitting login walls after a handful of profiles.

## Actor input object example

```json
{
  "usernames": [
    "cottonink"
  ],
  "includeRecentPosts": true,
  "maxPostsPerProfile": 12,
  "delaySeconds": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Merchant profile records with bio links and engagement metrics.

# 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": [
        "cottonink"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("zucchini_gopher_m2v/instagram-merchant-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": ["cottonink"] }

# Run the Actor and wait for it to finish
run = client.actor("zucchini_gopher_m2v/instagram-merchant-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": [
    "cottonink"
  ]
}' |
apify call zucchini_gopher_m2v/instagram-merchant-profile-scraper --silent --output-dataset

```

## MCP server setup

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