Import
import_from_instagram
Scrapes an Instagram creator's posts via Apify and imports them as media into the authenticated user's Outline media library.
Free, but rate-limited
Importing is free on every account tier — there is no Pro gate on building. Imports are rate-limited per user as an abuse guard, so a burst of calls can return
RATE_LIMITED; retry after a few minutes rather than treating it as a permission error.Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| handle | string | Yes | Instagram handle of the account to scrape. Leading '@' is stripped automatically — pass 'mycreator' or '@mycreator', both work. |
| outlineId | string | — | ID of the outline to import media into. Omit to target the authenticated user's own outline. |
Response
| Field | Type | What it means |
|---|---|---|
| handle | string | The bare Instagram handle that was scraped (leading @ already stripped). |
| profileUrl | string | Full Instagram profile URL for the scraped account, e.g. https://www.instagram.com/mycreator/. |
| displayName | string | Display name from the scraped Instagram profile. |
| bio | string | Bio text from the scraped Instagram profile. |
| partial | boolean | True if the Apify scrape returned fewer posts than requested (e.g. private account, rate-limited, or handle has fewer posts than the batch size). The import still ran on whatever was returned. |
| scrapedPostCount | number | Number of posts returned by the Apify scraper before filtering/import. |
| importedMedia | array | Array of media items successfully persisted to the outline media library. Each item has mediaId (string|number), mimeType (string), and sourceUrl (string). Items that failed to persist are excluded (not returned as nulls). |
Example
Request
json
{
"handle": "@saffron.ink",
"outlineId": "42"
}Response
json
{
"handle": "saffron.ink",
"profileUrl": "https://www.instagram.com/saffron.ink/",
"displayName": "Saffron Ink Studio",
"bio": "Fine line tattoos • Portland, OR • DMs open for bookings",
"partial": false,
"scrapedPostCount": 24,
"importedMedia": [
{
"mediaId": 318,
"mimeType": "image/jpeg",
"sourceUrl": "https://cdn.outline.build/media/318/saffron-ink-post-1.jpg"
},
{
"mediaId": 319,
"mimeType": "image/jpeg",
"sourceUrl": "https://cdn.outline.build/media/319/saffron-ink-post-2.jpg"
}
]
}When to use
Call this at step 3 of the create→curate→optimize loop, after get_guidance and get_taste_fingerprint have established the creator's goals and aesthetic, to bulk-populate the media library before building stacks with add_card. It is the fastest way to seed a new outline with a creator's existing visual content.
Gotchas
Watch out
- Rate limit is per user, not per handle — agent loops that scrape many accounts in sequence share one budget; hitting the limit returns RATE_LIMITED and no media is imported for that call.
- partial:true means the scrape returned less than a full batch; don't assume importedMedia is exhaustive — the account may have more posts than were fetched.
- APIFY_TOKEN must be configured in the environment; a missing or invalid token causes the scrape to throw and the tool returns SAVE_FAILED with no media persisted.
- importedMedia silently drops failed individual uploads (they are filtered out, not returned as errors); scrapedPostCount vs importedMedia.length tells you how many were lost.