Quickstart

One collector, two surfaces, one evidence model

Everything below runs against https://api.powerscraping.app. Whichever surface you use, the contract is the same: collection only runs against a declared authorized target, and every derived field in the result names the evidence it came from.

Collect with your own Instagram account, in your own browser, with the Power Scraping Collector extension (desktop Chrome, Edge or Brave). We never see your Instagram password. The REST API and the MCP connector start jobs and read results; the collecting itself always happens in the Collector.

The Collector: collecting in your own browser

No Instagram login of ours serves your jobs, and no third-party collection provider is involved. Every post is collected by the Power Scraping Collector browser extension, inside your own browser, under your own Instagram login, from your own device and network. Your Instagram password and session never leave your browser: we never receive, store or replay them. The extension has no cookies permission and never reads cookies. It has no standing access to instagram.com either: in manual mode it reads only the tab you click it on, and automatic mode needs a permission to open instagram.com, which the Collector asks for when you allow automatic collection and gives up whenever automatic collection is off.

1. Install

Use desktop Chrome, Edge or Brave. During the pilot the Collector is installed from a download rather than from a store:

  1. Download power-scraping-collector.zip (also linked from the dashboard's Collector panel) and unzip it into a folder you will keep.
  2. Open the browser's extensions page: chrome://extensions, edge://extensions or brave://extensions.
  3. Turn on Developer mode.
  4. Choose Load unpacked and select the unzipped folder.

A Chrome Web Store listing is coming. Phones, Safari and Firefox cannot collect; any browser can still read, search and download results.

2. Pair it with your account

In the dashboard's Collector panel, create a pairing code. It is short, single-use and expires after 10 minutes. Paste it into the Collector (its icon in the browser toolbar), check that it names your organisation, and confirm. The paired Collector works for the person who created the code: it collects the jobs that person submits, including jobs submitted with an API key that person created.

To stop using a browser, press Disconnect this browser in the Collector or Disconnect in the dashboard; either revokes it at once. We delete a disconnected browser's record - the name you gave it, the Instagram handle it reported and its timestamps - 30 days after it is disconnected, and the Instagram handle recorded against each job 30 days after the job finishes.

3. Collect: manual or automatic

The two ways the Collector gathers the posts of a declared target.
Mode What happens Account risk
Manual (the default) You open the target's posts on instagram.com yourself and press Send this post on each one. No automated activity is added to your account.
Automatic (opt-in, per browser) After you turn it on for that browser in the dashboard, acknowledge the account risk and allow it in the Collector, the Collector opens the target's profile and its posts in a visible tab, at a fixed slow pace, within small daily caps. Automated activity can lead Instagram to show warnings, apply temporary action blocks or restrict your account.

Either way, every job needs your click to start. A job waiting for your browser shows Waiting for your browser in the dashboard until you open the Collector and press Start. Once started, a manual job stays with your browser for 4 hours, renewed while the Collector is in use, and an automatic job for 30 minutes. The Collector stops at the first Instagram warning, challenge or logout. A challenge pauses that browser for 24 hours and switches automatic mode off until you turn it back on.

For a target declared as your own account (own_account), the Collector collects only while the browser is signed in to Instagram as that account - for Send this post as well as for jobs. A post already sent in the last 24 hours is a duplicate: it is not added again and not metered again.

What it sends, and what it never sends

Only these fields of the declared target's posts: post id, handle, permalink, dates, caption, location label, media type, links to the media on Instagram's servers, and like and comment counts. It never sends comments, other page text, your feed, your messages or who you follow. Posts of any other account are dropped on your device and again on our server. We never download the photos or videos themselves: records keep the links only. We then enrich, meter, store and export those records under your plan's retention rules.

Your account, your responsibility. Automated activity may trigger Instagram warnings, temporary action blocks or restrictions on your Instagram account. You must follow Instagram's terms, and you must have a lawful basis for every profile you collect - one of the four declared authorization bases below.

Authentication

Three credential kinds reach the same API, scoped to the same tenant.

Pick the credential that matches the caller.
Credential How it is presented Use it for
Session cookie psapp_session, set by /v1/auth/login, http-only The dashboard in a browser. Never used by server-side code.
API key Authorization: Bearer psa_live_… Your own backends, schedulers and scripts. A key acts for the person who created it: the collection jobs it submits run in that person's paired Collector.
OAuth access token Authorization: Bearer with a JWT for audience /mcp The MCP connector, issued to an AI client after you consent.

An API key is shown exactly once, when you create it. Only its prefix and a hash are stored, so a lost key is revoked and replaced, never recovered.

Step 0: declare what you may collect

This is not paperwork you can defer. Collection is refused with collection_not_authorized until two things are true: your account has accepted the current acceptable-use version, and the handle is an active authorized target with a basis and a reference. The Collector also drops, on your device and again on our server, any post that belongs to another account.

Valid values for authorization_basis.
Basis What it asserts Typical reference
own_account The profile belongs to your organisation. Internal account register entry
creator_contract You hold a signed agreement with the creator. Contract number and clause
client_mandate The account owner instructed you in writing. MSA or statement of work reference
public_interest_research Documented research in the public interest. Ethics approval or research protocol id

Revoke a target the moment its basis stops being true. Revocation takes effect immediately: the next job for that handle is refused. If the owner of a profile objects to its collection, we revoke it for them: that profile is then suppressed across the whole service and cannot be declared again, by you or by any other customer.

REST API quickstart

Eight curl calls from nothing to citable records you can download. The first four use a cookie jar because account and compliance actions need an interactive owner; the rest use an API key, which acts for the person who created it - you, in step 4. Before step 5, pair the Collector in your browser from the dashboard's Collector panel: collection runs there, and a collection job submitted with your key waits for your browser.

1. Create an account

curl -X POST https://api.powerscraping.app/v1/auth/signup \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{
        "email": "you@example.com",
        "password": "a-long-passphrase-you-chose",
        "organisation_name": "Acme Guides",
        "accept_terms": true,
        "business_use": true
      }'

Passwords must be at least 12 characters. "accept_terms": true records your agreement to the current Terms, Privacy notice and Acceptable use; without it the signup is refused with terms_not_accepted. "business_use": true confirms "I am using Power Scraping for my trade, business or profession" and records your business-customer declaration; Power Scraping is sold to business customers only, so the signup is refused without it as well. The response returns your tenant, user and plan, and sets the session cookie in cookies.txt.

2. Accept a document when it changes

curl -X POST https://api.powerscraping.app/v1/legal/accept \
  -H "Content-Type: application/json" -b cookies.txt \
  -d '{"document": "acceptable_use"}'

Signing up records the versions current at the time. When a document is updated, GET /v1/me lists it under legal with "is_current": false, and this call records the new version - the document is terms_of_service, privacy_notice or acceptable_use. Omit version and the current published version is recorded. Read it first at https://api.powerscraping.app/v1/legal/acceptable-use.

This is the one endpoint that insists on a signed-in user: the cookie from step 1, or the button in the dashboard. An API key or an MCP token is refused with permission_denied, because accepting the terms is the customer's own act and nothing running unattended may perform it on their behalf.

3. Declare an authorized target

curl -X POST https://api.powerscraping.app/v1/targets \
  -H "Content-Type: application/json" -b cookies.txt \
  -d '{
        "platform": "instagram",
        "username": "trattoriadaoscar",
        "authorization_basis": "client_mandate",
        "authorization_reference": "MSA-2026-114, schedule 2"
      }'

4. Mint an API key

curl -X POST https://api.powerscraping.app/v1/keys \
  -H "Content-Type: application/json" -b cookies.txt \
  -d '{"name": "ingest worker"}'
{
  "id": "key_7c1f…",
  "name": "ingest worker",
  "prefix": "psa_live_9Qd2",
  "active": true,
  "api_key": "psa_live_9Qd2………",
  "notice": "Copy this key now. It is shown once and cannot be retrieved again."
}

Export it for the calls below: export PSAPP_KEY=psa_live_9Qd2…. Store it in your secret manager, not in source control.

The key acts for you, the person who created it: every collection job it submits runs in your paired Collector, and waits there for you to press Start. A key with no creator cannot start collection jobs.

5. Submit a collection job

curl -X POST https://api.powerscraping.app/v1/jobs \
  -H "Authorization: Bearer $PSAPP_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: oscar-2026-09-17" \
  -d '{
        "kind": "collect",
        "target_username": "trattoriadaoscar",
        "platform": "instagram",
        "params": {"max_posts": 50}
      }'

Job kinds: collect (bounded recent posts) and enrich_only (re-enrich the last release). Re-sending the same Idempotency-Key returns the original job instead of starting a second one.

A collection job does not run on our servers. It runs in the Collector, in the paired browser of the person who submitted it - for an API key, the person who created the key - and only after that person presses Start. If that person has no paired browser, the job is refused with collector_required.

6. Poll the job

curl https://api.powerscraping.app/v1/jobs/job_5f2a \
  -H "Authorization: Bearer $PSAPP_KEY"
{
  "id": "job_5f2a",
  "kind": "collect",
  "target_username": "trattoriadaoscar",
  "status": "succeeded",
  "posts_processed": 48,
  "records_written": 48,
  "release_id": "rel_2026_09_17_01",
  "is_terminal": true,
  "results_available": true
}

Statuses are awaiting_browser (waiting for the Collector: open it and press Start), pending, running, succeeded, failed and cancelled. A job that stopped at an Instagram warning, challenge or logout did exactly what it should - the Collector stops there by design. It is not a bug to retry around.

7. Read the records

curl "https://api.powerscraping.app/v1/jobs/job_5f2a/results?limit=10&offset=0" \
  -H "Authorization: Bearer $PSAPP_KEY"

8. Download every record

curl -OJ "https://api.powerscraping.app/v1/jobs/job_5f2a/export?format=csv" \
  -H "Authorization: Bearer $PSAPP_KEY"

format=csv or format=jsonl. The whole job comes back in one file, in order, with its evidence citations - no paging. A job that has not succeeded answers 409. The dashboard's Download CSV and Download JSONL buttons fetch the same files. Cells that would start a spreadsheet formula are neutralised, so a caption cannot become a live formula.

Reading a record and its citations

Each record carries its evidence items and the citations that bind fields to them. A field with no resolvable citation is not written at all, so a null means "we could not evidence this", never "we did not get round to it".

{
  "record_id": "rec_8d31f0a4",
  "source_url": "https://www.instagram.com/p/Cx1y2z3/",
  "creator_handle": "trattoriadaoscar",
  "venue": {"name": "Trattoria da Oscar", "place_id": null},
  "location": {"city": "Milan", "confidence": 0.94},
  "assessment": {"sentiment": "positive", "explicit_rating": null},
  "price": {"mentions_eur": [14.0, 22.0], "signal": "mid_range"},
  "unknown_fields": ["assessment.explicit_rating"],
  "citations": [
    {
      "field": "venue.name",
      "evidence_id": "ev_01",
      "modality": "caption",
      "excerpt": "finally back at @trattoriadaoscar for the cotoletta",
      "method": "caption_mention",
      "confidence": 0.97
    },
    {
      "field": "price.mentions_eur",
      "evidence_id": "ev_03",
      "modality": "caption",
      "excerpt": "cotoletta 22 euro, calice di rosso 14",
      "method": "price_extraction",
      "confidence": 0.93
    }
  ]
}

Every job also records what was collected, when, and under which declared authorization basis, and every field carries the evidence it was derived from. Download every record of a job, citations included, from GET /v1/jobs/{job_id}/export?format=csv or ?format=jsonl.

Errors

Every failure you can act on has the same shape and a stable machine-readable code.

{
  "error": {
    "code": "collection_not_authorized",
    "message": "No active authorized target for 'trattoriadaoscar' on instagram.",
    "detail": {"platform": "instagram", "username": "trattoriadaoscar"}
  }
}
The codes worth handling explicitly.
HTTP Code What to do
401 unauthenticated Present a valid credential. A revoked key reads the same as a missing one.
402 quota_exceeded The period allowance is spent, so jobs stop. Wait for the next period or move to a larger plan.
403 collection_not_authorized Declare the target, or accept the current acceptable-use version - the latter from a signed-in session, not from a key or token.
403 permission_denied The action needs an account owner, not an API key.
404 not_found No such item in your tenant. Anything belonging to another tenant answers 404 as well, deliberately.
409 conflict Already declared, or the job has already finished and cannot be cancelled.
409 collector_required The person the job would run for - you, or for an API key the person who created it - has no paired Collector. Pair one in the dashboard's Collector panel and submit again.
409 subscription_exists Checkout refused: the account already has a subscription. Change plan in the billing portal, POST /v1/billing/portal.
409 terms_not_accepted, business_declaration_required Checkout refused: accept the current Terms, and confirm you are buying for your trade, business or profession - the business-use declaration you made at sign-up counts, or send "business_customer": true.
422 invalid_request Read detail.field; it names the offending field.
429 rate_limited Back off and retry.

MCP connector quickstart

The connector exposes the same evidence-grounded records to an AI client over the Model Context Protocol, Streamable HTTP transport, protocol revision 2025-06-18.

Collecting from a chat needs the Collector. Before collection works, the chat user needs the Power Scraping Collector installed and paired on a desktop browser (Chrome, Edge or Brave). Until then start_collection answers collector_required, with a link to set it up. Reading and searching records works from any client, phones included.

Add the server

In Claude, ChatGPT or an IDE agent that supports remote MCP servers, add a connector with this URL:

https://api.powerscraping.app/mcp

The client discovers authorization by itself: the server answers an unauthenticated call with 401 and a WWW-Authenticate header pointing at its RFC 9728 metadata. Registration, consent and token exchange then happen without you pasting a secret anywhere.

OAuth endpoints, for a client that needs them spelled out.
Purpose Path
Protected-resource metadata (RFC 9728) /.well-known/oauth-protected-resource
Authorization-server metadata (RFC 8414) /.well-known/oauth-authorization-server
Dynamic client registration (RFC 7591) /oauth/register
Authorization (PKCE required) /oauth/authorize
Token /oauth/token
Revocation (RFC 7009) /oauth/revoke

The tools

What the assistant can call once you have consented.
Tool What it does
list_authorized_targets The handles this account may collect, with basis and reference.
authorize_target Declare a new target, naming the basis and an auditable reference.
start_collection Submit a collection job for a declared target. Returns a job id, or collector_required with a setup link when no Collector is paired. The job then runs in that person's Collector once they click to start it.
get_job_status Poll the job, including the reason a job stopped.
get_venue_records Read a page of enriched records with their citations.
search_records Filter finished records by city, price band, sentiment or tag.
get_usage The plan, the period allowance and what is left of it.

A typical conversation

  1. list_authorized_targets to see what may be collected.
  2. authorize_target if the handle is missing — the basis is required.
  3. get_usage before a large run, so the job is not refused mid-way.
  4. start_collection, then get_job_status until it succeeds. If it answers collector_required, follow the link, pair the Collector on a desktop browser, and ask again.
  5. get_venue_records or search_records to answer the question.

Tell the assistant to quote citations rather than fill gaps. When a field comes back null it is genuinely unknown, and the whole point of this connector is that the model can say so.

Endpoint reference

The full generated specification lives at https://api.powerscraping.app/api/openapi.json, with interactive docs at https://api.powerscraping.app/api/docs.

The endpoints this quickstart uses.
Method and path Credential Purpose
GET /v1/plans None The published plan catalogue.
GET /v1/legal/acceptable-use None The current terms and their version.
POST /v1/auth/signup None Create a tenant and its owner. Needs "accept_terms": true and "business_use": true.
POST /v1/auth/login None Start a dashboard session.
POST /v1/legal/accept Session only Record acceptance of a policy version. An API key or an MCP token is refused with permission_denied, deliberately: this row is the account's proof of who agreed to the terms and when, so an unattended agent must not be able to bind the customer to them.
GET /v1/me Any The account, plan and usage behind the credential, and under legal whether each accepted document is still current.
GET POST /v1/targets Session (write), any (read) List or declare authorized targets.
DELETE /v1/targets/{id} Session Revoke a declaration.
GET POST /v1/keys Session (owner) List or create API keys.
DELETE /v1/keys/{id} Session (owner) Revoke a key.
POST /v1/collectors/pairing-codes Session only A single-use pairing code for the Collector, valid for 10 minutes, with the organisation name the Collector will show.
GET /v1/collectors Session only Your paired browsers; an owner sees every browser in the workspace.
PATCH /v1/collectors/{id} Session only Turn automatic collection on ("guided_enabled": true with "accept_account_risk": true, your own browser only) or off.
DELETE /v1/collectors/{id} Session only Disconnect a browser. It is refused from its next request on.
GET POST /v1/jobs Any List or submit jobs.
POST /v1/jobs/{id}/cancel Any Cancel a job that has not finished.
GET /v1/jobs/{id}/results Any A page of records with citations.
GET /v1/jobs/{id}/export?format=csv|jsonl Any Every record of a succeeded job, as one CSV or JSON Lines download.
GET /v1/billing/usage Any Metered position for the current period.
POST /v1/billing/checkout Session (owner) Open Stripe Checkout for a first paid plan. Needs the business-use declaration made at sign-up, or "business_customer": true.
POST /v1/billing/portal Session (owner) Open the Stripe billing portal: change plan, update card, cancel.
POST /mcp OAuth bearer The MCP connector endpoint.