[Instagram APIs](/docs/api.md#instagram) 

# Instagram Profile Download

Export a full public Instagram profile as a ZIP file with media, captions, post metadata, manifest.json, and posts.csv. Authenticated runs are recommended in async mode. Pricing depends on account eligibility and profile size. See the Instagram profile downloader in your dashboard for your starting price.

 POST `/v1/instagram/profile-download`

[Parameters](#parameters) [Response](#response) [Errors](#errors) [More examples](#more-examples) 

**Authenticate every request**

Send `Authorization: Bearer YOUR_API_KEY`. [Get an API key →](/docs/guides/authentication.md) 

## Parameters

Send these fields in a flat JSON body. Add `_run` to choose execution options.

- **`profile` string Required**
  Instagram username, @handle, or profile URL to export as a ZIP file. Minimum length: 1. Maximum length: 2000.

- **`limit` integer Optional**
  Optional maximum number of posts to include. Omit this field to export the full public profile. Preferred name; maxPosts remains supported. Minimum: 1. Maximum: 100000.

### Advanced & compatibility inputs 1

- **`maxPosts` integer Optional**
  Optional maximum number of posts to include. Omit this field to export the full public profile. You can also use limit. Minimum: 1. Maximum: 100000.

## Response

Every response describes a run. Read `result` once `run_status` is `succeeded`.

- **`run_id`**
  The run to track. Keep it when contacting support.

- **`run_status`**
  Queued, running, waiting for sign-in, succeeded, or failed. Check this even after an HTTP 200.

- **`status_url`**
  Poll this URL while the run is pending. Keep the same run instead of starting another request.

- **`result`**
  The endpoint’s returned data. The example is illustrative; actual fields may be empty or unavailable.

- **`error`**
  On failure, inspect its code, message, retryable and action fields.

### View the complete output schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "The result begins with an export ID. A completed run returns artifact details, download expiry and collection statistics. partial_success means some media could not be downloaded; inspect failed_media.",
  "anyOf": [
    {
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean",
          "const": true
        },
        "export_id": {
          "type": "string",
          "description": "Export identifier. Poll the run until it succeeds before downloading."
        },
        "status": {
          "type": "string",
          "enum": [
            "completed",
            "partial_success",
            "pending"
          ]
        },
        "file_name": {
          "type": "string"
        },
        "download_url": {
          "type": "string",
          "description": "Short-lived signed download URL. It can be a pending:// placeholder before the artifact is ready."
        },
        "download_url_expires_at": {
          "type": [
            "string",
            "null"
          ]
        },
        "expires_at": {
          "type": [
            "string",
            "null"
          ]
        },
        "error_code": {
          "type": [
            "string",
            "null"
          ]
        },
        "error_message": {
          "type": [
            "string",
            "null"
          ]
        },
        "max_posts": {
          "type": [
            "number",
            "null"
          ]
        },
        "truncated": {
          "type": "boolean"
        },
        "profile": {
          "type": "object",
          "properties": {
            "id": {
              "type": [
                "string",
                "null"
              ]
            },
            "username": {
              "type": "string"
            },
            "full_name": {
              "type": [
                "string",
                "null"
              ]
            },
            "is_private": {
              "type": "boolean"
            },
            "total_posts": {
              "type": "number"
            },
            "profile_pic_url": {
              "type": [
                "string",
                "null"
              ]
            },
            "authenticated": {
              "type": "boolean"
            }
          },
          "required": [
            "id",
            "username",
            "full_name",
            "is_private",
            "total_posts",
            "profile_pic_url",
            "authenticated"
          ],
          "additionalProperties": false
        },
        "result_summary": {
          "type": "object",
          "properties": {
            "postsDiscovered": {
              "type": "number"
            },
            "mediaDiscovered": {
              "type": "number"
            },
            "estimatedBytes": {
              "type": "number"
            },
            "downloadedFiles": {
              "type": "number"
            },
            "failedFiles": {
              "type": "number"
            },
            "skippedFiles": {
              "type": "number"
            },
            "truncated": {
              "type": "boolean"
            },
            "postsDownloaded": {
              "type": "number"
            }
          },
          "required": [
            "postsDiscovered",
            "mediaDiscovered",
            "estimatedBytes",
            "downloadedFiles",
            "failedFiles",
            "skippedFiles",
            "truncated",
            "postsDownloaded"
          ],
          "additionalProperties": false
        },
        "failed_media": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "post_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "post_code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "post_url": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "post_index": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "media_index": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "media_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "file_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "failure_reason": {
                "type": "string"
              }
            },
            "required": [
              "post_id",
              "post_code",
              "post_url",
              "post_index",
              "media_index",
              "media_id",
              "file_name",
              "failure_reason"
            ],
            "additionalProperties": false
          }
        }
      },
      "required": [
        "success",
        "export_id",
        "status",
        "file_name",
        "download_url",
        "download_url_expires_at",
        "expires_at",
        "error_code",
        "error_message",
        "max_posts",
        "truncated",
        "profile",
        "result_summary",
        "failed_media"
      ],
      "additionalProperties": false
    },
    {
      "type": "object",
      "properties": {
        "export_id": {
          "type": "string"
        }
      },
      "required": [
        "export_id"
      ],
      "additionalProperties": false
    }
  ]
}
```

### View a polled run response

```json
{
  "run_id": "00000000-0000-4000-8000-000000000001",
  "task_key": "instagram-profile-download",
  "task_name": "Instagram Profile Download",
  "run_status": "succeeded",
  "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001",
  "result": {
    "success": true,
    "export_id": "id-1",
    "status": "completed",
    "file_name": "Stylish Shoreditch Loft with Balcony",
    "download_url": "https://example.com/item-1",
    "download_url_expires_at": "https://example.com/item-1",
    "expires_at": "sample",
    "error_code": "sample",
    "error_message": "sample",
    "max_posts": 1.5,
    "truncated": true,
    "profile": {
      "id": "id-1",
      "username": "Stylish Shoreditch Loft with Balcony",
      "full_name": "Stylish Shoreditch Loft with Balcony",
      "is_private": true,
      "total_posts": 180,
      "profile_pic_url": "https://example.com/item-1",
      "authenticated": true
    },
    "result_summary": {
      "postsDiscovered": 1.5,
      "mediaDiscovered": 1.5,
      "estimatedBytes": 1.5,
      "downloadedFiles": 1.5,
      "failedFiles": 1.5,
      "skippedFiles": 1.5,
      "truncated": true,
      "postsDownloaded": 1.5
    },
    "failed_media": [
      {
        "post_id": "id-1",
        "post_code": "sample",
        "post_url": "https://example.com/item-1",
        "post_index": 1.5,
        "media_index": 1.5,
        "media_id": "id-1",
        "file_name": "Stylish Shoreditch Loft with Balcony",
        "failure_reason": "sample"
      }
    ]
  },
  "error": null
}
```

## Errors & retries

- `400` Fix the fields listed in `errors` before retrying.

- `428` Connect the requested website account using the returned sign-in link.

- `429` Wait for the duration in `Retry-After`.

- `5xx` Retry transient failures with backoff. Keep the request ID.

A failed run has its own error inside the response. Retry it only when `error.retryable` is true.

[Validation, pagination and recovery →](/docs/api/request-guide.md) 

## More examples

### Async request with polling

```bash
RUN=$(curl -s -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"profile":"natgeo"}')

RUN_ID=$(echo "$RUN" | jq -er '.run_id // empty') || { echo "$RUN" >&2; exit 1; }
POLL_DELAY=3

while true; do
  RESULT=$(curl -s -H "Authorization: Bearer YOUR_API_KEY" "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/$RUN_ID")
  STATUS=$(echo "$RESULT" | jq -r '.run_status')
  if [[ "$STATUS" =~ ^(succeeded|failed|errored|cancelled|canceled|expired)$ ]]; then
    echo "$RESULT"
    break
  fi
  sleep "$(awk "BEGIN { print $POLL_DELAY * (0.9 + ($RANDOM % 21) / 100) }")"
  POLL_DELAY=$((POLL_DELAY < 30 ? POLL_DELAY * 2 : 30))
  [ "$POLL_DELAY" -gt 30 ] && POLL_DELAY=30
done
```

```javascript
const runResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "profile": "natgeo"
}),
});

const runPayload = await runResponse.json();
if (!runResponse.ok) throw new Error(JSON.stringify(runPayload));
const runId = runPayload.run_id;
if (!runId) throw new Error("Run ID not found in response");
let pollDelayMs = 3000;

while (true) {
  const resultResponse = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + runId, {
    headers: { Authorization: "Bearer YOUR_API_KEY" },
  });
  const result = await resultResponse.json().catch(() => ({}));
  if (resultResponse.status === 429 || [502, 503, 504].includes(resultResponse.status)) {
    const retryAfter = resultResponse.headers.get("retry-after");
    await new Promise((resolve) => setTimeout(resolve, retryAfter ? Number(retryAfter) * 1000 : pollDelayMs));
    continue;
  }
  if (!resultResponse.ok) throw new Error(`Status request failed: ${resultResponse.status}`);
  const status = result.run_status;
  if (["succeeded", "failed", "errored", "cancelled", "canceled", "expired"].includes(status)) {
    console.log(result);
    break;
  }
  await new Promise((resolve) => setTimeout(resolve, pollDelayMs * (0.9 + Math.random() * 0.2)));
  pollDelayMs = Math.min(pollDelayMs * 2, 30000);
}
```

```python
import random
import time
import requests

run_response = requests.post(
    "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
    "profile": "natgeo"
},
)
run_payload = run_response.json()
if not run_response.ok:
    raise RuntimeError(run_payload)
run_id = run_payload.get("run_id")
if not run_id:
    raise ValueError("Run ID not found in response")
poll_delay = 3.0

while True:
    result_response = requests.get(
        "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/runs/" + run_id,
        headers={"Authorization": "Bearer YOUR_API_KEY"},
    )
    if result_response.status_code == 429 or result_response.status_code in (502, 503, 504):
        retry_after = result_response.headers.get("Retry-After")
        time.sleep(float(retry_after) if retry_after else poll_delay)
        continue
    result_response.raise_for_status()
    result = result_response.json()
    status = result.get("run_status")
    if status in ("succeeded", "failed", "errored", "cancelled", "canceled", "expired"):
        print(result)
        break
    time.sleep(poll_delay * random.uniform(0.9, 1.1))
    poll_delay = min(poll_delay * 2, 30.0)
```

### Wait-for-results request

```bash
curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"profile":"natgeo","_run":{"async":false}}'
```

```javascript
const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "profile": "natgeo",
  "_run": {
    "async": false
  }
}),
});

const result = await response.json();
console.log(result);
```

```python
import requests

response = requests.post(
    "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
    "profile": "natgeo",
    "_run": {
        "async": False
    }
},
)
result = response.json()
print(result)
```

### Canonical & compatibility routes

You can also send the same JSON body to `/v1/tasks/instagram-profile-download/runs`.

 Example request  Request mode Wait for resultsAsync + polling

```bash
curl -X POST "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"profile":"natgeo","_run":{"async":false}}'
```

```javascript
const response = await fetch("https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "profile": "natgeo",
  "_run": {
    "async": false
  }
}),
});

const result = await response.json();
console.log(result);
```

```python
import requests

response = requests.post(
    "https://api-ingress-worker-staging.browsable-staging.workers.dev/v1/instagram/profile-download",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
    "profile": "natgeo",
    "_run": {
        "async": False
    }
},
)
result = response.json()
print(result)
```

Requests can return before a run finishes. Check run_status and poll status_url when needed.

### View example response

 Example response  Illustrative 

```json
{
  "run_id": "00000000-0000-4000-8000-000000000001",
  "task_key": "instagram-profile-download",
  "task_name": "Instagram Profile Download",
  "run_status": "succeeded",
  "status_url": "/v1/runs/00000000-0000-4000-8000-000000000001",
  "result": {
    "success": true,
    "export_id": "id-1",
    "status": "completed",
    "file_name": "Stylish Shoreditch Loft with Balcony",
    "download_url": "https://example.com/item-1",
    "download_url_expires_at": "https://example.com/item-1",
    "expires_at": "sample",
    "error_code": "sample",
    "error_message": "sample",
    "max_posts": 1.5,
    "truncated": true,
    "profile": {
      "id": "id-1",
      "username": "Stylish Shoreditch Loft with Balcony",
      "full_name": "Stylish Shoreditch Loft with Balcony",
      "is_private": true,
      "total_posts": 180,
      "profile_pic_url": "https://example.com/item-1",
      "authenticated": true
    },
    "result_summary": {
      "postsDiscovered": 1.5,
      "mediaDiscovered": 1.5,
      "estimatedBytes": 1.5,
      "downloadedFiles": 1.5,
      "failedFiles": 1.5,
      "skippedFiles": 1.5,
      "truncated": true,
      "postsDownloaded": 1.5
    },
    "failed_media": [
      {
        "post_id": "id-1",
        "post_code": "sample",
        "post_url": "https://example.com/item-1",
        "post_index": 1.5,
        "media_index": 1.5,
        "media_id": "id-1",
        "file_name": "Stylish Shoreditch Loft with Balcony",
        "failure_reason": "sample"
      }
    ]
  },
  "error": null
}
```

[Understand the response →](#response)

---
Source: https://browsable-api-ux-staging.pages.dev/docs/api/endpoints/post-instagram-profile-download
