Skip to content

How to Run an Apify Actor and Export a Dataset to CSV

Start an Actor, track its execution, download saved results and retrieve every dataset page through Console, Python API or your AI agent with Apify MCP.

Dievio Team · Growth Systems · November 6, 2026 · 6 min read

API code window connected to a CSV export

To export an Apify Actor's results, start its run, save the returned run ID, wait for completion and read defaultDatasetId. Request the dataset's items as CSV or JSON. If a finished run already exists, reuse its Dataset ID: downloading those saved results does not require another Actor run.

You can do this manually in Apify Console, from your application using the API, or through your AI agent with Apify MCP. The same three things matter in every route: correct input, recorded run identity and a complete result export.

Choose Console, API or an AI-agent workflow

Three ways to run the same Actor
RouteUseful whenWhat you manage
Apify ConsoleYou want an editable form and a first CSVInput, Run options, reports and download.
Apify APIYour application needs repeatable processingAuthentication, run ID, status, storage and retries.
Apify MCPYour compatible AI agent should coordinate the workflowActor choice, scope, spending cap and output requirements.

For a first manual run, open the Actor, choose Try for free, sign in and edit Input in Console. Review Pricing, set a small result limit and spending cap, then start. Inspect Output and the source-coverage report before choosing CSV or JSON from the dataset export controls.

Build input for the specific Actor

There is no universal scraper payload. Twitter followers, website contacts and Zillow details accept different inputs and return different row types. Inspect the selected Actor's current Input, Output and README before copying an example.

Twitter Followers Scraper field reference for target usernames, follower and following selection, limits and output mode
Read-only reference for the concrete Twitter Actor input used in this API and MCP example.

The figure shows the read-only reference for the Twitter Followers Scraper. In this guide, it is the concrete example: request five follower connections for a public username, with username output explicitly selected. For the full collection workflow, see exporting Twitter followers and following.

{
  "userNameList": ["nasa"],
  "getFollowers": true,
  "maxFollowers": 5,
  "getFollowing": false,
  "outputMode": "usernames"
}

The follower limit belongs in this Actor's input. An API charge cap is a separate run option. A technical endpoint such as https://api.apify.com/v2 should remain unchanged; referral parameters belong on editorial Apify links.

Use the right identifier at each step

Run and export endpoints
ActionEndpoint under api.apify.comKeep
Start the ActorPOST /v2/actors/{actorId}/runsdata.id, the run ID.
Check that runGET /v2/actor-runs/{runId}Status, defaultDatasetId and defaultKeyValueStoreId.
Download rowsGET /v2/datasets/{datasetId}/itemsThe exported response body.

Use owner~actor-name in the start URL, such as x_guru~twitter-follower-scraper. The run ID identifies one execution. The Dataset ID identifies saved rows. Do not put a run ID into the Dataset endpoint.

Send your Apify token in the Authorization bearer header and keep it in an environment variable or your application's credential store. Follow the Actor's documented output if it uses a named dataset or another storage location instead of the default dataset.

Dievio

Your next customer starts here.

Find decision-makers by role, company and location. Build your next prospect list in Dievio.

Find my leads

Free audience preview · No credit card

Find leadsExample
FounderSoftwareUnited States
AM
Alex MorganFounder & CEO · Northstaralex@northstar.example
JC
Jamie ChenCo-founder · Formlyjamie@formly.example
Work emailsCompany detailsCSV export

Run a small Python example and save its CSV

Install requests and set APIFY_TOKEN. This example starts a chargeable Actor run with a small PPE spending cap. It writes the run ID to actor-run.json before polling. To resume checking an existing execution, set APIFY_RUN_ID; that skips the start request.

import json
import os
import time
from pathlib import Path

import requests

base = "https://api.apify.com/v2"
session = requests.Session()
session.headers["Authorization"] = (
    f"Bearer {os.environ['APIFY_TOKEN']}"
)
payload = {
    "userNameList": ["nasa"],
    "getFollowers": True,
    "maxFollowers": 5,
    "getFollowing": False,
    "outputMode": "usernames",
}
run_id = os.environ.get("APIFY_RUN_ID")
if not run_id:
    start = session.post(
        f"{base}/actors/"
        "x_guru~twitter-follower-scraper/runs",
        params={"maxTotalChargeUsd": 0.10},
        json=payload,
        timeout=20,
    )
    start.raise_for_status()
    run_id = start.json()["data"]["id"]
    Path("actor-run.json").write_text(
        json.dumps({"runId": run_id}),
        encoding="utf-8",
    )
print("Run ID:", run_id)

deadline = time.monotonic() + 180
while time.monotonic() < deadline:
    response = session.get(
        f"{base}/actor-runs/{run_id}", timeout=20
    )
    response.raise_for_status()
    run = response.json()["data"]
    if run["status"] == "SUCCEEDED":
        break
    if run["status"] in {
        "FAILED", "ABORTED", "TIMED-OUT"
    }:
        raise RuntimeError(
            f"Inspect run {run_id}: {run['status']}"
        )
    time.sleep(3)
else:
    raise TimeoutError(
        f"Check existing run {run_id}; do not restart"
    )

export = session.get(
    f"{base}/datasets/"
    f"{run['defaultDatasetId']}/items",
    params={"format": "csv", "bom": 1},
    timeout=30,
)
export.raise_for_status()
Path("actor-results.csv").write_bytes(export.content)

The 180-second client wait is not a guarantee that the run will finish in that time. If it expires, inspect the existing run using the recorded ID. A client timeout does not automatically stop an Actor. Review logs and source coverage before treating a successful dataset as complete.

Export all JSON pages without starting again

Use JSON for nested objects, joins or batch imports. The reader below uses the authenticated Session from the earlier example and assumes a completed, unchanged dataset. It deliberately leaves row-skipping transformations off. Persist each completed offset only after the destination accepts its rows.

def read_dataset_pages(session, dataset_id, limit=1000):
    url = (
        "https://api.apify.com/v2/datasets/"
        f"{dataset_id}/items"
    )
    offset = 0
    while True:
        response = session.get(
            url,
            params={
                "format": "json",
                "offset": offset,
                "limit": limit,
            },
            timeout=30,
        )
        response.raise_for_status()
        rows = response.json()
        if not isinstance(rows, list):
            raise ValueError("Expected Dataset items list")
        if not rows:
            break
        yield offset, rows
        offset += len(rows)
        total = response.headers.get(
            "X-Apify-Pagination-Total"
        )
        if total is not None and offset >= int(total):
            break

For 2,130 saved items with pages of 1,000, the expected offsets are 0, 1,000 and 2,000. Increase by the actual returned count. If you later add clean, skip-empty or other transformations, review the endpoint's pagination semantics instead of assuming the same loop still applies.

Dataset pagination reads already saved rows. Actor continuation collects additional source results. They are different operations: use that Actor's documented PAGINATION.nextInput when collection itself is incomplete, and keep each new run and dataset in your ledger.

Let your AI agent coordinate the run through Apify MCP

Add https://mcp.apify.com to a compatible MCP client and authorize your Apify account. Follow the official connection guide. You can ask for the same bounded workflow in ordinary language.

Use Apify MCP. Inspect the current schema for
x_guru/twitter-follower-scraper.
Collect five follower connections for nasa.
Set outputMode to usernames, getFollowers true,
maxFollowers 5 and getFollowing false.
Set callOptions.maxTotalChargeUsd to 0.10.
Record the run ID and wait for completion.
Retrieve every page of the default dataset.
Export CSV and report actual row count,
source coverage and any unfinished work.
If the run exists, reuse it. Do not start
another paid run just to download its rows.

fetch-actor-details provides the current contract. call-actor starts the execution and returns status and storage IDs; it does not itself return the complete dataset. Use get-actor-run, get-dataset-items with limit/offset and get-key-value-store-record for the remaining steps.

Use callOptions.maxTotalChargeUsd for the MCP run cap rather than inserting it into Actor input. A compatible client can also expose an Actor as a dedicated tool. The official MCP server repository documents available tools and their behavior.

Handle partial runs, empty output and retries

Retry the operation that actually failed
SituationNext action
Start request timed out before returning an IDCheck run history against time and input before repeating the POST; it may already have started.
Status GET failed temporarilyKeep the same run ID and retry with a delay; respect Retry-After.
Run failed, timed out or was abortedInspect logs and any saved output. Label retained rows partial.
Dataset GET returned 401 or 403Check credentials and account access to that storage.
Successful run has no rowsRead the Actor's source and billing reports; zero matches and source failure are different outcomes.

Production integrations should keep a run ledger, bounded retry policy and destination upserts. The Python example demonstrates the basic flow; it does not implement a durable job queue. If you later use n8n, the same sequence is POST → Wait/status loop → dataset GET. n8n is optional; direct API code is sufficient.

See the official references for starting an Actor, reading run status and Dataset exports. Choose your next source in the Actor directory, or follow the two-Actor follower-to-email workflow.

Keep reading

Build your first list.

100 free credits. No credit card required.

Start free