# Instagram Contact Scraper — Email & Phone Extractor (`khadinakbar/instagram-contact-scraper`) Actor

Extract emails and phone numbers from public Instagram profiles, using business and creator account fields, bio text and bio links. No login needed; works with Apify MCP and the API.

- **URL**: https://apify.com/khadinakbar/instagram-contact-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Social media, Lead generation, MCP servers
- **Features:** Limited permissions
- **Stats:** 94 total users, 27 monthly users, 98.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 contact founds

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?

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

### What is Instagram Contact Scraper?

Instagram Contact Scraper takes Instagram usernames or profile URLs and returns one row per profile with the contact details the account publishes: the business email and phone from the contact button, emails and phone numbers written in the bio, bio links, WhatsApp numbers from click-to-chat links, emails spelled out to dodge scrapers ("name at site dot com"), the external website, plus follower count, verification, business-account flag and category. A `hasContact` flag tells you at a glance which profiles can be reached. Influencer marketers, agencies, sales teams and AI agents use it to turn a list of handles into an outreach list, with no Instagram login.

### Why marketers use it for creator outreach

- **Every public contact source in one row.** Contact-button details and bio text are both checked, and the best email and phone are put in `email` and `phone`.
- **Link-in-bio and WhatsApp aware.** WhatsApp click-to-chat links in the bio are read straight into `whatsapp` (and `phone` when no other number exists). `linkInBioService` names the service the profile links to (Linktree, Beacons, Stan, Bento and more). With `expandBioLinks` the pages behind those links are opened too.
- **Reachable or not, at a glance.** `hasContact` is `true` when an email or phone was found.
- **Lower price for profiles without contacts.** Profiles with no published contact are billed at a smaller rate. With `onlyWithContact` they are skipped (no row saved); from 2026-11-23 a skipped profile is billed at that same lower rate, because it is still looked up.
- **Context for prioritizing.** `followersCount`, `isVerified`, `isBusinessAccount` and `businessCategory` help you decide who to contact first.
- **Handles or URLs.** Paste `@name`, `name` or the full profile URL; duplicates are skipped.

### What's new

- **0.2.1:** optional **email check** (`emailCheck`): format, mail server, throwaway-domain and role-address flags on each found email, at no extra charge. Optional **engagement** (`includeEngagement`) is built but switches on only when its price is added (14-day notice first); until then it does nothing and costs nothing.
- **0.2.0:** WhatsApp numbers (`whatsapp`), emails spelled out in the bio, `linkInBioService`, a clean `PARTIAL` stop before the time limit, and an `agentSummary` sentence in `OUTPUT`. Prices are unchanged by this release; the already-announced prices start 2026-11-23.
- Parallel lookups (5 at a time) and the cheapest available data route first.

### How to use it

**Get contacts for a list of creators:**

```json
{
  "usernames": ["humansofny", "natgeo", "https://www.instagram.com/nasa/"]
}
```

**Keep only profiles that publish a contact:**

```json
{
  "usernames": ["humansofny", "natgeo", "nasa"],
  "onlyWithContact": true,
  "maxItems": 50
}
```

| Input | What it controls |
|---|---|
| `usernames` | Instagram usernames, @handles or profile URLs. Required. |
| `onlyWithContact` | Save only profiles where an email or phone was found (default off). From 2026-11-23 skipped profiles are billed as no-contact lookups |
| `expandBioLinks` | Also open link-in-bio pages (Linktree, Beacons, websites; up to 3 per profile) to find an email, phone or WhatsApp number when the profile shows no email (default off; the Console form pre-fills it on) |
| `emailCheck` | Check each found email with DNS and built-in lists and add `emailStatus` (likely-deliverable, risky, invalid) plus `emailMxFound`, `emailDisposable`, `emailRole`. A mail server existing does not prove the mailbox does. Default off, no extra charge |
| `includeEngagement` | Average likes, comments, engagement rate and last post date from recent public posts. Not active yet (see What's new); default off |
| `maxItems` | Most profiles to save in one run, which also caps the cost |

**Find more contacts through link-in-bio pages:**

```json
{
  "usernames": ["humansofny", "natgeo", "nasa"],
  "expandBioLinks": true
}
```

Each row says where its contact came from in `contactSource` (`profile`, `bio` or `bio-link`). Profiles that could not be loaded are listed in `OUTPUT.unresolvedUsernames`, so nothing is dropped silently. A run that finishes with some profiles unresolved, or that stops a little before its time limit, reports `PARTIAL` (never a silent success); profiles it did not start are listed in `OUTPUT.notProcessedUsernames` so you can run them again.

**Check the emails you find (free):**

```json
{
  "usernames": ["humansofny", "natgeo", "nasa"],
  "expandBioLinks": true,
  "emailCheck": true
}
```

This is a quick screen, not full verification. For a deeper list check use [Email Address Validator](https://apify.com/khadinakbar/email-address-validator); for audience quality use [Instagram Fake Follower Auditor](https://apify.com/khadinakbar/instagram-fake-follower-auditor). Follower lists are not available without a login and are not offered here.

Still looking for accounts? Start with **Instagram User Search Scraper** (linked below) to find profiles by keyword, then pass the usernames in here.

### Output: contact data you receive

This row has the same fields as a real result, but every value is fictional to protect the account owner's privacy. Fields with no value are left out of the row:

```json
{
  "username": "example_studio",
  "fullName": "Example Studio",
  "userId": "1234567890",
  "email": "hello@example-studio.com",
  "bioEmails": ["hello@example-studio.com"],
  "bioPhones": [],
  "bioLinks": ["https://example-studio.com/shop"],
  "externalUrl": "https://example-studio.com/shop",
  "biography": "Handmade ceramics. Collabs: hello@example-studio.com",
  "isBusinessAccount": false,
  "followersCount": 48210,
  "isVerified": false,
  "isPrivate": false,
  "profileUrl": "https://www.instagram.com/example_studio/",
  "hasContact": true,
  "scrapedAt": "2026-10-01T00:19:51.312Z"
}
```

| Field | What it contains |
|---|---|
| `email`, `phone` | The best email and phone found, from the contact button first, then the bio |
| `bioEmails`, `bioPhones` | Every email and phone number written in the bio |
| `bioLinks`, `externalUrl` | The profile's links and website |
| `hasContact` | `true` when an email or phone was found |
| `followersCount`, `isVerified`, `isBusinessAccount`, `businessCategory` | Context for prioritizing outreach |
| `biography`, `fullName`, `profileUrl` | Who the account is |

`OUTPUT` in the default key-value store counts profiles, contacts found and profiles without contacts for the whole run.

### Example workflow: an influencer outreach list

A skincare brand has 200 creator handles from a hashtag search. They run them with `onlyWithContact` turned on, so only reachable creators are saved and the rest are billed at the lower no-contact rate. They sort by `followersCount`, keep accounts where `isBusinessAccount` is true for paid partnerships, and pass the `email` column to [Email Address Validator](https://apify.com/khadinakbar/email-address-validator) before sending the first pitch.

### Pricing

This Actor uses **Pay per event**. Apify platform usage is included in the event price. Each saved profile is one event: a contact event when an email or phone was found, or a smaller no-contact event when it was not. Each run also has one start event. The live Pricing tab on this page shows the current prices.

- 100 profiles, 40 with contacts = 40 contact events + 60 no-contact events + 1 start event.
- With `onlyWithContact` on, the same run saves 40 rows. Until 2026-11-22 it is billed 40 contact events + 1 start event; from 2026-11-23 the 60 skipped profiles are also billed as no-contact events (same total as above).
- New prices from 2026-11-23: $0.008 per profile with a contact, $0.0056 per profile without one (announced with Apify's 14-day notice).
- `maxItems` caps each run, so it doubles as a cost ceiling.
- With `expandBioLinks` on, a profile whose contact is found only on its link-in-bio page is billed as a contact event. The page visit itself is not charged.

#### Free Apify plan

Runs from a free Apify plan process up to 25 profiles per run. Every option and field is available. Paid Apify plans have no per-run limit.

### Creator outreach with AI agents (MCP)

Connect this Actor to an AI agent through [Apify MCP](https://mcp.apify.com) and ask in plain language:

> Find contact details for these 20 Instagram creators. Keep only the ones with an email or phone, and give me the email, follower count and website for each.

Agent checklist:

1. Pass handles or URLs in `usernames`; set `onlyWithContact: true` when the user wants reachable profiles only.
2. Read rows with `get-dataset-items`; use `hasContact` to sort reachable profiles first.
3. Read `OUTPUT` for counts of contacts found and profiles without contacts; `OUTPUT.agentSummary` is a ready-made one-sentence answer.
4. Use `profileUrl` as the stable ID when joining with other data.

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/khadinakbar~instagram-contact-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"usernames": ["humansofny", "nasa"], "onlyWithContact": true}'
```

### Related Instagram tools from the same developer

| Your next step | Use | Why |
|---|---|---|
| When you still need to find accounts by keyword | [Instagram User Search Scraper](https://apify.com/khadinakbar/instagram-user-search-scraper) | Profiles for any niche or keyword |
| When you want the people commenting on a post | [Instagram Post Engagers Scraper](https://apify.com/khadinakbar/instagram-post-engagers-scraper) | Commenter usernames from public posts and Reels |
| When you want to check audience quality first | [Instagram Fake Follower Auditor](https://apify.com/khadinakbar/instagram-fake-follower-auditor) | Fake-follower risk score per profile |
| When you then want contacts from the linked websites | [Contact Details Scraper](https://apify.com/khadinakbar/contact-details-scraper) | Emails, phones and socials from each website |
| When you then want to check which emails are deliverable | [Email Address Validator](https://apify.com/khadinakbar/email-address-validator) | Syntax, mail server, disposable and role checks |

### Best results

| Starting situation | Helpful action | Expected outcome |
|---|---|---|
| A long list of creators | Turn on `onlyWithContact` | Only reachable profiles in the dataset |
| Creators who link a website instead of an email | Pass `externalUrl` values to Contact Details Scraper | Emails from the creator's own site |
| Budget limits | Set `maxItems` | A fixed maximum cost per run |
| Brand partnerships | Filter on `isBusinessAccount` and `businessCategory` | Accounts set up for business contact |

### Builder's note

I found that creators publish contact details in two places, the contact button and the bio text, so the Actor checks both and puts the best email and phone in their own columns. I learned that many profiles publish no contact at all, which is why those rows cost less and can be left out of the dataset with `onlyWithContact`.

### FAQ

#### Can I pass profile URLs instead of usernames?

Yes. Usernames, @handles and full Instagram profile URLs all work and can be mixed.

#### Where do the emails come from?

From what the account publishes: the business contact button and the bio text. For emails on a linked website, pass `externalUrl` to Contact Details Scraper.

#### What does hasContact mean?

It is `true` when the profile publishes an email or a phone number, and `false` when it publishes neither.

#### Which profiles work best?

Public creator and business profiles. Business and creator accounts often fill the contact button, which gives the most reliable email and phone.

#### Why are some fields missing from a row?

Fields with no value are left out of the row to keep it compact. For example, `phone` appears only when a phone number was found.

### Responsible use

This Actor collects contact details that Instagram accounts publish, which is personal data protected by laws such as the GDPR and CCPA. Use it with a lawful basis such as legitimate business interest, follow CAN-SPAM and anti-spam rules, honor opt-out requests, and respect Instagram's terms. Read Apify's guide on [whether web scraping is legal](https://blog.apify.com/is-web-scraping-legal/) for more context. Instagram is a trademark of Meta Platforms, Inc. This independent Actor is not affiliated with, associated with, or endorsed by Instagram or Meta. For questions or bugs, open a ticket in the Issues tab.

# Changelog

This Actor's version history is a separate document: https://apify.com/khadinakbar/instagram-contact-scraper/changelog.md

# Actor input Schema

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

One or more Instagram accounts to extract contact info from. Accepts bare usernames ('nike'), @-handles ('@nasa'), or full profile URLs ('https://instagram.com/hubspot'). Business and creator accounts are most likely to have email/phone. Returns one record per profile with email, phone, WhatsApp, bio links and a hasContact flag.

## `onlyWithContact` (type: `boolean`):

When true, only profiles that have at least one email or phone number are pushed to the dataset. Profiles with no contact data are skipped (no row saved). Until 2026-11-22 skipped profiles are free; from 2026-11-23 each skipped profile is billed as a no-contact lookup (every profile is looked up either way) and counts toward Max profiles. Useful for lead-gen pipelines where you only want actionable rows. Default: false (all profiles saved).

## `expandBioLinks` (type: `boolean`):

When true and a profile shows no email, the Actor opens its public link-in-bio pages (Linktree, Beacons, Stan, Bento, personal website; up to 3) and looks for an email, a tel: phone link or a WhatsApp click-to-chat link there. Contacts found this way are saved in linkEmails / linkPhones / linkWhatsapp and marked contactSource 'bio-link'. A profile that gains a contact this way is billed as a contact-found row; the page visits themselves are free. Default: false.

## `emailCheck` (type: `boolean`):

When true, each email found is checked with plain DNS and built-in lists: valid format, mail server (MX) exists, throwaway-domain flag, role-address flag (info@, sales@...), and an overall emailStatus (likely-deliverable, risky, invalid). It does not prove the mailbox exists. No extra charge. Default: false.

## `includeEngagement` (type: `boolean`):

Adds average likes, average comments, engagement rate and last post date from the profile's recent public posts. NOT available yet: it switches on automatically when its price event is added to this Actor's pricing (announced with Apify's 14-day notice). Until then the flag is accepted, has no effect and costs nothing. Default: false.

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

Stop after processing this many profiles (saved profiles plus, from 2026-11-23, billed skips in onlyWithContact mode). Useful for budget control on large lists. Defaults to unlimited (all supplied usernames). Free Apify plan runs process up to 25 profiles per run.

## Actor input object example

```json
{
  "usernames": [
    "nike",
    "@garyvee",
    "https://www.instagram.com/hubspot/"
  ],
  "onlyWithContact": false,
  "expandBioLinks": true,
  "emailCheck": false,
  "includeEngagement": false,
  "maxItems": 100
}
```

# Actor output Schema

## `contacts` (type: `string`):

Dataset items with username, email, phone, whatsapp, bioEmails, bioPhones, bioLinks, linkInBioService, hasContact, source and profileUrl; plus emailStatus and related flags when emailCheck is on.

## `summary` (type: `string`):

Run outcome, totalProfiles, contactsFound, itemsPushed and a one-sentence agentSummary.

## `runSummary` (type: `string`):

Machine-readable RUN_SUMMARY record mirroring OUTPUT for integrations that read RUN_SUMMARY directly.

# 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": [
        "humansofny",
        "natgeo",
        "nasa"
    ],
    "expandBioLinks": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/instagram-contact-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": [
        "humansofny",
        "natgeo",
        "nasa",
    ],
    "expandBioLinks": True,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/instagram-contact-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": [
    "humansofny",
    "natgeo",
    "nasa"
  ],
  "expandBioLinks": true
}' |
apify call khadinakbar/instagram-contact-scraper --silent --output-dataset

```

## MCP server setup

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