# Instagram Profile Email Scraper (`lance_api/instagram-profile-email-scraper`) Actor

Extract public email addresses and rich Instagram profile data, including followers, bio, links, verification status, and business metadata. Ideal for lead generation, CRM enrichment, influencer discovery, and automation.

- **URL**: https://apify.com/lance_api/instagram-profile-email-scraper.md
- **Developed by:** [LanceAPI](https://apify.com/lance_api) (community)
- **Categories:** Social media, Lead generation, AI
- **Features:** Limited permissions
- **Stats:** 24 total users, 5 monthly users, 97.4% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.00 / 1,000 profile 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

## Instagram Profile Email Scraper API

**Instagram Profile Email Scraper** turns Instagram profile URLs into structured public profile data plus any email address that profile publishes — and, when the profile publishes none, reads the website that profile links to and picks up the address there. One dataset item per profile, a clear status for every profile, and two-part pricing: a low base price per returned result, plus an `email-found` charge only when an address is actually delivered.

No Instagram login, cookies, browser session, proxy or external data-source credentials are required from you.

### Key features

- **Batch input:** one profile URL or up to 100 per run.
- **Public email detection:** addresses published in the profile's public contact fields, biography and bio links.
- **Second pass over the linked website:** when the profile itself publishes no address, the Actor reads the site it links to — contact page, about page, and the privacy or terms page small shops use instead — and keeps the address it finds there. Client-side sites are handled by reading their JavaScript bundle.
- **Structured enrichment:** username, user ID, display name, category, followers, following, account flags, links and avatar URLs when available.
- **One item per profile, always:** every valid unique input produces exactly one dataset item, including failures — so a batch never silently loses a row.
- **Explicit statuses:** eight documented statuses and a stable `errorCode`, so a downstream job can branch without parsing prose.
- **Ready-made views:** All profiles, Emails found, No email found, Failed profiles.
- **Run summary:** counts written to the run's key-value store as `RUN_SUMMARY`.

### Quick input example

```json
{
  "profileUrls": [
    "https://www.instagram.com/example.creator/"
  ]
}
```

### Short output example

```json
{
  "username": "example.creator",
  "profileUrl": "https://www.instagram.com/example.creator/",
  "displayName": "Example Creator",
  "emails": ["hello@examplecreator.com"],
  "followersCount": 24500,
  "followingCount": 312,
  "category": "Digital creator",
  "status": "EMAIL_FOUND",
  "errorCode": null
}
```

### Try it in 3 steps

1. Paste one or more Instagram profile URLs.
2. Click **Start**.
3. Open the **Dataset** to inspect or export the results.

Start with one profile to confirm the output format, or process batches of up to 100 profile URLs per run. When you are ready, scale with Apify Tasks, schedules, API calls or integrations.

### Table of contents

- [What does this Actor do?](#what-does-this-actor-do)
- [Input](#input)
- [API usage](#api-usage)
- [Output](#output)
- [Complete output field reference](#complete-output-field-reference)
- [Status values](#status-values)
- [Where are email addresses found?](#where-are-email-addresses-found)
- [Dataset views](#dataset-views)
- [Run summary](#run-summary)
- [Pricing](#pricing)
- [Public data and responsible use](#public-data-and-responsible-use)
- [FAQ](#faq)
- [Limitations](#limitations)
- [Support](#support)

### What does this Actor do?

This Actor is an **Instagram profile email scraper** for profile-level contact discovery. It accepts Instagram profile URLs (including share links with query strings), resolves each one to a canonical username, retrieves that profile's public data, extracts the addresses the profile publishes, and stores one result item per profile.

It does **not** search for profiles by keyword, scrape follower lists, search hashtags, read posts or Reels for addresses, follow links that are not published by the profile itself, access private content, or solve CAPTCHA challenges.

Duplicates are collapsed: submitting the same profile twice in one run processes it once and returns one item, so you are never billed twice for the same profile in the same run.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `profileUrls` | array of strings | Yes | One or more Instagram profile URLs. Query strings are accepted and normalized. Minimum 1, maximum 100. |
| `scrapeWebsiteContacts` | boolean | No | Default `true`. When a profile publishes no address of its own, visit the website or link-in-bio page listed on that profile and read the addresses it publishes. Adds no extra charge; adds a few seconds for those profiles only. |
| `maxWebsitePages` | integer | No | Default `3`, range 1–5. How many pages of a linked site may be read, starting from the homepage. |
| `websiteTimeoutSeconds` | integer | No | Default `15`, range 5–30. Total time allowed for one website, including page discovery. A slow site is cut off rather than allowed to hold up the run. |
| `websiteCrossDomainEmails` | boolean | No | Default `false`. Keep an address found on the site whose domain differs from the site's own (an agency, a parent brand, a press contact) in the `website` evidence block, but do not add it to `emails`. Set `true` to accept those addresses too. |

Accepted forms — all of these resolve to the same profile:

```text
https://www.instagram.com/example.creator/
instagram.com/example.creator
https://instagram.com/Example.Creator/?igsh=EXAMPLE
@example.creator
example.creator
```

Rejected forms — a post, Reel, story or any sub-path is not a profile:

```text
https://www.instagram.com/p/CxYz123/
https://www.instagram.com/example.creator/reels/
```

Invalid values never abort the run. They are skipped, counted in the run summary, and listed there so you can correct them. If every submitted value is invalid, the run still succeeds and returns a single `INVALID_INPUT` item explaining why — the item is the answer, so the run does not have to fail to deliver it.

### API usage

The Actor slug is `lance_api/instagram-profile-email-scraper`.

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/lance_api~instagram-profile-email-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"profileUrls":["https://www.instagram.com/example.creator/"]}'
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('lance_api/instagram-profile-email-scraper').call({
  profileUrls: ['https://www.instagram.com/example.creator/'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("lance_api/instagram-profile-email-scraper").call(
    run_input={"profileUrls": ["https://www.instagram.com/example.creator/"]}
)
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

### Output

One dataset item per valid unique input profile. The order of the fields below is the order they appear in the Dataset.

#### Full output example

```json
{
  "actorVersion": "1.0.0",
  "inputUrl": "https://www.instagram.com/example.creator/?igsh=EXAMPLE",
  "profileUrl": "https://www.instagram.com/example.creator/",
  "username": "example.creator",
  "userId": "52410962",
  "eimuId": null,
  "displayName": "Example Creator",
  "category": "Digital creator",
  "emails": ["hello@examplecreator.com", "partners@examplecreator.com"],
  "externalUrls": ["https://examplecreator.com"],
  "bioLinks": [
    {
      "title": "Work with us",
      "url": "https://examplecreator.com/contact",
      "linkType": "external"
    }
  ],
  "threadsUrl": null,
  "profilePictureUrl": "https://example.com/profile.jpg",
  "profilePictureUrlHd": "https://example.com/profile-hd.jpg",
  "followersCount": 24500,
  "followingCount": 312,
  "isVerified": false,
  "isPrivate": false,
  "isBusinessAccount": true,
  "isProfessionalAccount": true,
  "businessPhoneNumber": null,
  "businessContactMethod": "EMAIL",
  "highlightReelCount": 4,
  "website": {
    "url": "https://examplecreator.com",
    "finalUrl": "https://examplecreator.com/",
    "status": "ok",
    "reason": null,
    "httpStatus": 200,
    "jsSuspected": false,
    "pagesCrawled": 3,
    "elapsedMs": 1840,
    "candidatesTried": 1,
    "emails": [
      {
        "email": "hello@examplecreator.com",
        "method": "mailto",
        "confidence": 0.95,
        "crossDomain": false,
        "sourceUrl": "https://examplecreator.com/contact"
      }
    ],
    "phones": [],
    "addresses": []
  },
  "status": "EMAIL_FOUND",
  "scrapedAt": "2026-11-05T08:00:00.000Z",
  "error": null,
  "errorCode": null
}
```

### Complete output field reference

#### Input and identity

| Field | Type | Description |
| --- | --- | --- |
| `actorVersion` | string | Code version that produced the item. |
| `inputUrl` | string | The value you submitted, unchanged. |
| `profileUrl` | string or null | Canonical profile URL. |
| `username` | string or null | Normalized lowercase username. |
| `userId` | string or null | Instagram numeric user ID when available. |
| `eimuId` | string or null | Additional profile identifier when the data source returns one. |

#### Profile information

| Field | Type | Description |
| --- | --- | --- |
| `displayName` | string or null | Display name or full name. |
| `category` | string or null | Public profile category. |
| `isVerified` | boolean or null | Verified badge. |
| `isPrivate` | boolean or null | Private account flag. |
| `isBusinessAccount` | boolean or null | Business account flag. |
| `isProfessionalAccount` | boolean or null | Professional or creator account flag. |

#### Contact information

| Field | Type | Description |
| --- | --- | --- |
| `emails` | array of strings | Deduplicated, lowercased, validated public addresses. Empty when none were found. |
| `businessPhoneNumber` | string or null | Public business phone number when the profile publishes one. |
| `businessContactMethod` | string or null | Public contact method, for example `EMAIL`. |

#### Audience information

| Field | Type | Description |
| --- | --- | --- |
| `followersCount` | integer or null | Follower count. |
| `followingCount` | integer or null | Following count. |
| `highlightReelCount` | integer or null | Number of highlight reels. |

#### Profile links and media

| Field | Type | Description |
| --- | --- | --- |
| `externalUrls` | array of strings | Public external URLs returned with the profile. |
| `bioLinks` | array of objects | `{ title, url, linkType }` for each structured bio link. |
| `threadsUrl` | string or null | Threads URL when one is published. |
| `profilePictureUrl` | string or null | Profile picture URL. |
| `profilePictureUrlHd` | string or null | High-resolution profile picture URL. |

#### Website second pass

| Field | Type | Description |
| --- | --- | --- |
| `website` | object or null | What the linked site published, when it was visited. `null` when the profile carried no crawlable link, when the pass is switched off, or when the profile already published an address of its own. |
| `website.url` | string or null | Link taken from the profile that was crawled. |
| `website.finalUrl` | string or null | Where the request landed after redirects. |
| `website.status` | string | `ok` (an address on the site's own domain was found), `no_contact` (the site was read and publishes nothing usable), `error` (the page could not be read), `skipped` (nothing to crawl). |
| `website.reason` | string or null | Why the pass ended the way it did — for example `js_rendered_page` or `parked`. |
| `website.httpStatus` | integer or null | HTTP status of the homepage. |
| `website.jsSuspected` | boolean | `true` when the page body is rendered by JavaScript; its copy then lives in a bundle, which is read separately. |
| `website.pagesCrawled` | integer | Pages that were actually read successfully. |
| `website.elapsedMs` | integer | Time spent on the site. |
| `website.candidatesTried` | integer | How many links from the profile were tried before giving up (1 or 2). |
| `website.emails` | array of objects | Every address the site published, with `email`, `method`, `confidence`, `crossDomain` and `sourceUrl`. |
| `website.phones` | array of objects | Phone numbers the site published, with `phone`, `e164`, `method`, `confidence` and `sourceUrl`. |
| `website.addresses` | array of objects | Postal addresses the site published, with `address`, `method`, `confidence` and `sourceUrl`. |

#### Processing status

| Field | Type | Description |
| --- | --- | --- |
| `status` | string | One of the eight statuses below. |
| `errorCode` | string or null | Stable machine-readable reason. `null` when `status` is `EMAIL_FOUND` or `NO_EMAIL_FOUND`. |
| `error` | string or null | Human-readable sentence for a failed item. Never contains internal detail. |
| `scrapedAt` | string | ISO 8601 timestamp of when the item was produced. |

### Status values

| Status | Meaning | Base result charge? | `email-found` charge? |
| --- | --- | --- | --- |
| `EMAIL_FOUND` | At least one valid public address was delivered. | Yes | Yes |
| `NO_EMAIL_FOUND` | The profile was read, but publishes no address. | Yes | No |
| `PROFILE_NOT_FOUND` | The account does not exist. | Yes | No |
| `PRIVATE_OR_LOGIN_REQUIRED` | The profile is private or behind a login wall. | Yes | No |
| `BLOCKED_OR_RATE_LIMITED` | The data source refused or throttled the request. | Yes | No |
| `FETCH_FAILED` | The profile could not be read right now; retry later. | Yes | No |
| `INVALID_INPUT` | The submitted value is not an Instagram profile URL. | Yes | No |
| `FREE_USAGE_LIMIT_REACHED` | The free-plan allowance for this period is used up. | Yes | No |

On the free plan, profiles are capped at **50 per day, 500 per calendar month and 1000 in total**
(UTC), and a single free run accepts **at most 20 profiles** while only **one free run per account
may be in progress at a time**. Once any cap is reached, further profiles in that run return
`FREE_USAGE_LIMIT_REACHED` with a message quoting the exact used/limit numbers of the cap that
applies. Only profiles that were actually looked up count toward the allowance — duplicate inputs,
retries and blocked profiles do not. Paid plans have no such cap. The daily and monthly allowances
reset automatically; nothing needs to be done on your side.

A batch over the 20-profile free ceiling, or a second free run started while another is still
running, processes nothing and returns **one** `FREE_USAGE_LIMIT_REACHED` item naming the limit that
was hit. Both cases leave the run itself successful: the refusal is the answer, not a crash, and a
caller reads it from the item's `status`/`errorCode` rather than from the run's exit code. Split the
batch, or wait for the running one to finish, and start again.

`errorCode` narrows the failure without changing the `status`:

| `errorCode` | Typical `status` |
| --- | --- |
| `PROFILE_NOT_FOUND` | `PROFILE_NOT_FOUND` |
| `PROFILE_IS_PRIVATE` | `PRIVATE_OR_LOGIN_REQUIRED` |
| `UPSTREAM_RATE_LIMITED` | `BLOCKED_OR_RATE_LIMITED` |
| `UPSTREAM_QUOTA_EXHAUSTED` | `BLOCKED_OR_RATE_LIMITED` |
| `UPSTREAM_AUTH_FAILED` | `FETCH_FAILED` |
| `UPSTREAM_TIMEOUT` | `FETCH_FAILED` |
| `UPSTREAM_ERROR` | `FETCH_FAILED` |
| `MALFORMED_RESPONSE` | `FETCH_FAILED` |
| `PROFILE_METADATA_UNAVAILABLE` | `FETCH_FAILED` |
| `FREE_USAGE_LIMIT_REACHED` | `FREE_USAGE_LIMIT_REACHED` |
| `FREE_BATCH_LIMIT_EXCEEDED` | `FREE_USAGE_LIMIT_REACHED` |
| `FREE_ACTIVE_RUN_LIMIT` | `FREE_USAGE_LIMIT_REACHED` |
| `FREE_USAGE_SERVICE_UNAVAILABLE` | `FETCH_FAILED` |
| `INVALID_PROFILE_URL` | `INVALID_INPUT` |
| `BATCH_LIMIT_EXCEEDED` | `INVALID_INPUT` |
| `DATASET_WRITE_FAILED` | `FETCH_FAILED` |
| `INTERNAL_ERROR` | `FETCH_FAILED` |

New `errorCode` values may be added over time. Branch on `status` for stable behaviour; treat `errorCode` as extra detail.

### Where are email addresses found?

Only in fields that belong to the requested profile and are publicly visible, plus the website that same profile publishes:

1. **Public contact fields** on the profile (for example a published business or contact email).
2. **The biography text.**
3. **The bio link URL**, when the link itself is a `mailto:` or contains an address.
4. **The title of a bio link**, when the title is an address.
5. **The profile's own website**, and only when steps 1–4 produced nothing. The Actor reads the homepage and the contact, about or imprint pages it links to, decodes `mailto:` links, `[at]`/`[dot]` obfuscation, JSON-LD and microdata, and — for client-side sites whose HTML is an empty shell — the site's own JavaScript bundle. If those still yield nothing, it takes one more look at the refund, privacy or terms page, because small shops often publish their only address there.

Addresses from the website are added to the same `emails` list and are marked in `website.emails` with the page they came from (`sourceUrl`) and the method that proved them. An address on a different domain than the site — an agency, a payment processor, a regulator named in a privacy notice — stays in the evidence block but is not added to `emails`, unless you set `websiteCrossDomainEmails: true`.

Every address is normalized to lowercase, de-duplicated and format-checked. Obvious non-addresses are dropped: template placeholders such as `your@email.com`, documentation and example domains, and strings that only look like addresses.

Addresses are never mined from unrelated parts of the profile data. A profile that publishes nothing on Instagram and links to a site that publishes nothing either yields `NO_EMAIL_FOUND` — that outcome is a normal, correctly billed result rather than an error.

### Dataset views

The dataset ships with four views, so you do not have to build filters:

| View | What it shows |
| --- | --- |
| **All profiles** | Every item, with `username`, `profileUrl`, `emails`, `status`, `displayName`, `followersCount`, `category` first. |
| **Emails found** | Only `EMAIL_FOUND` items, with the addresses and the core profile fields. |
| **No email found** | Profiles that were read successfully but publish nothing. |
| **Failed profiles** | Everything with an `errorCode`, including the public `error` sentence. |

### Run summary

Each run writes a `RUN_SUMMARY` record to its key-value store, also linked from the run's Output tab. It contains:

- `status`: `SUCCEEDED`, `PARTIAL` or `FAILED`;
- `input`: how many values were submitted, how many were unique, how many were duplicates, how many were invalid (with the invalid values listed), how many were processed, and how many were left unprocessed;
- `output`: dataset rows, `EMAIL_FOUND`, `NO_EMAIL_FOUND`, `PROFILE_NOT_FOUND`, `PRIVATE_OR_LOGIN_REQUIRED`, `BLOCKED_OR_RATE_LIMITED`, `FETCH_FAILED`, `FREE_USAGE_LIMIT_REACHED`, total addresses, addresses that came from a linked website, how many profiles had their website visited, total failures;
- `errorTaxonomy`: a count per `errorCode`;
- `notes`: present only when something needs explaining — for example, profiles skipped because the run reached the maximum charge set for it. `input.notProcessed` counts those, and they are never added to `output.failed`;
- `settings`: the per-run profile cap and the concurrency used.

It is safe to log or forward: it contains business counts only.

### Pricing

Two events, unchanged from previous versions of this Actor.

| Event | When it is charged | Price |
| --- | --- | --- |
| Base result | Once per dataset item, charged automatically by Apify | $0.001 per item |
| `email-found` | Once per profile whose item delivers at least one address | $0.006 (FREE) / $0.004 (BRONZE) / $0.0035 (SILVER) / $0.003 (GOLD, PLATINUM, DIAMOND) |

What this means in practice:

- **Several addresses in one profile = one `email-found` charge.** Two addresses are not two charges.
- **No address = no `email-found` charge.** You still pay the base result price for the item.
- **One profile per run = at most one `email-found` charge**, even if the profile is submitted twice.
- **The website pass adds no extra charge.** An address it finds is charged as the same single `email-found`, and if it finds nothing you pay nothing for the attempt.
- **Retries and any internal recovery cost you nothing extra.** Only the two events above are ever billed.
- **A failed item can never carry an `email-found` charge**, because the charge is raised only after the item has been written to the dataset.

### Public data and responsible use

This Actor reads publicly visible profile data. It does not log in, does not bypass privacy settings and does not return anything a logged-out visitor cannot see. You remain responsible for how you use the data: comply with Instagram's terms, applicable privacy law (for example GDPR or CCPA) and anti-spam rules in your jurisdiction. Use the addresses for legitimate business communication and honour opt-out requests.

### FAQ

**What input do I need?**
One or more Instagram profile URLs. Post links, Reel links and other sub-paths are rejected as `INVALID_INPUT`.

**Can I process many profiles at once?**
Yes, up to 100 unique profiles per run. Duplicates are collapsed and processed once.

**Where do you find email addresses?**
In the profile's own public contact fields, biography and bio links — and, when those publish nothing, on the website that same profile links to. See [Where are email addresses found?](#where-are-email-addresses-found).

**Are the addresses verified?**
They are validated for format, normalized and de-duplicated, and they are published by the profile itself. They are not SMTP-verified, so an address can still be stale.

**Does it work with private profiles?**
No. A private profile returns `PRIVATE_OR_LOGIN_REQUIRED` with no data.

**Do I need Instagram cookies or a login?**
No.

**What happens when no email is found?**
You get one item with `status: "NO_EMAIL_FOUND"`, the profile fields that were available, and only the base result charge.

**How is a paid result counted?**
One base result charge per dataset item plus one `email-found` charge per item that contains at least one address.

**Can I use it through an API?**
Yes — REST, the JavaScript client, the Python client, Tasks, schedules and webhooks all work.

**Can I export the results?**
Yes: JSON, CSV, Excel or XML from the Dataset, or through the API.

### Limitations

- Profile-level only: no keyword search, follower lists, hashtags, posts or Reels.
- The website pass reads only the links the profile itself publishes, and only when the profile published no address. It follows no third-party links found on that site.
- A site that hides everything behind a login, a bot challenge (for example a Cloudflare interstitial) or client-side rendering it never exposes in its bundle cannot be read; the `website.status` field says which of those happened.
- One Instagram profile per input value; a share link that points at a post is not a profile.
- Address discovery is limited to what the profile and its own site publish; many creators publish nothing.
- Availability depends on public profile data being reachable. A blocked or throttled request returns `BLOCKED_OR_RATE_LIMITED`, and the same profile may succeed on a later run.
- Very large batches can take a while; the run summary reports progress and outcomes when it finishes.

### Support

Open an issue from the Actor's **Issues** tab with the run ID and the affected profile URL. Please do not paste tokens or private data into an issue.

# Actor input Schema

## `profileUrls` (type: `array`):

Submit one or more Instagram creator profile URLs. You can process up to 100 URLs per run.

## `scrapeWebsiteContacts` (type: `boolean`):

When a profile publishes no email of its own, visit the website (or link-in-bio page) listed on that profile and read the addresses it publishes — contact page, about page, and the privacy or terms page that small shops often use instead. Costs no provider credits; adds a few seconds for those profiles only. Turn off to keep every run strictly to Instagram data.

## `maxWebsitePages` (type: `integer`):

How many pages of a linked website may be read, starting from the homepage. Ignored when the website pass is off.

## `websiteTimeoutSeconds` (type: `integer`):

Total time allowed for one website, including page discovery. A slow site is cut off rather than allowed to hold up the run.

## `websiteCrossDomainEmails` (type: `boolean`):

Off by default: an address on a different domain than the site (an agency, a parent brand, a press contact) stays in the evidence block but is not added to `emails`. Turn on when you want those too — for example a personal site that routes all mail to the owner's company domain.

## Actor input object example

```json
{
  "profileUrls": [
    "https://www.instagram.com/hex.gar"
  ],
  "scrapeWebsiteContacts": true,
  "maxWebsitePages": 3,
  "websiteTimeoutSeconds": 15,
  "websiteCrossDomainEmails": false
}
```

# Actor output Schema

## `profileResults` (type: `string`):

Open the default dataset to view or export one structured result per processed Instagram profile URL.

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

Per-run totals in plain language: how many profiles were requested, how many were unique, how many were processed, how many emails were found, and how many profiles failed and why.

# 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 = {
    "profileUrls": [
        "https://www.instagram.com/hex.gar"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("lance_api/instagram-profile-email-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 = { "profileUrls": ["https://www.instagram.com/hex.gar"] }

# Run the Actor and wait for it to finish
run = client.actor("lance_api/instagram-profile-email-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 '{
  "profileUrls": [
    "https://www.instagram.com/hex.gar"
  ]
}' |
apify call lance_api/instagram-profile-email-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lance_api/instagram-profile-email-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/POchHcX3os4uS1xYy/builds/al97sqbKCAM7GSJti/openapi.json
