herascrape
Guides

Migrating from HikerAPI

Swap the base URL, swap the header, translate the paths.

Same data, fewer endpoints, lower price. HikerAPI's 154 paths collapse to 37 here, because they expose their internal transport — the same capability appears under /v1, /v2, /v3, /gql, /g1, /g2 and /a2 — and we pick the source internally.

Fastest path: skip to the agent prompt at the bottom. Paste it into Claude Code, Cursor or your agent of choice and it rewrites your client — the prompt points the agent at llms-full.txt, so it pulls these docs itself. Everything above is that reference, for reading by hand.

Three mechanical changes

HikerAPIherascrape
Base URLhttps://api.hikerapi.comhttps://api.herascrape.com
Auth headerx-access-keyx-api-key
Paths154 versioned37 RESTful

Then two rules: one cursor for paging, and drop the noise parameters.

Pagination

HikerAPI uses a different paging parameter on almost every endpoint. We use one opaque cursor.

HikerAPIherascrape
page_id, next_page_idcursor
max_id, next_max_id, min_id, reels_max_idcursor
end_cursorcursor
page_tokencursor
profile_grid_items_cursor, repost_next_max_idcursor

Read the next token from next_cursor and loop while has_more is true. Full details in Pagination.

Two endpoints keep Instagram's native paging instead, because the token is structural to their response: /posts/{id}/comments pages on min_id, and /users/{id}/posts pages on max_id.

Parameters to delete

HikerAPIWhy it is gone
safe_intOur ids are always strings. Always safe.
forcePrivacy handling is automatic.
amountDeprecated on HikerAPI too. Page with cursor.
flat, rank_token, expand_suggestion, can_support_threadingInternal defaults.

Responses

Read this before you touch your parsing code.

Like HikerAPI, we return Instagram's JSON as Instagram sends it. We do not rename fields, reshape objects, or trim responses. If your code already reads HikerAPI's v1/v2 payloads, the fields are in the same places.

The differences that will actually bite:

  • List responses are wrapped. HikerAPI returns a bare array on many endpoints; ours return {items, next_cursor, has_more}. Read items.
  • HikerAPI's v1 and v2 variants of the same call return different shapes. We have one endpoint per capability, so whichever variant you were on, you land on one shape. If you were using a v1 route, check the fields — we generally serve the richer private-API source.
  • No short/full modes. You always get the full object.

Addressing

Users are addressed by numeric id. The only username path is GET /users/username/{username}, which returns the profile including pk. Where your code called a by-username sub-resource — stories, highlights, followers — resolve once, cache the id, then use the id endpoints. Resolving costs double, so caching is worth real money at volume.

Posts take either the pk or the shortcode on /posts/{id}, so by-id, by-code and by-url calls all collapse into one. Pull the code out of an instagram.com/p/<code>/ URL and pass it.

Endpoint translation

Users

HikerAPIherascrape
GET /v2/user/by/username, /v1/user/by/username, /a2/user, /v2/userstream/by/usernameGET /users/username/{username}
GET /v2/user/by/id, /v1/user/by/id, /gql/user/by/id, /gql/user/web_profile_info, /v2/userstream/by/idGET /users/{id}
GET /v1/user/by/urlExtract the username, then GET /users/username/{username}
GET /gql/user/about, /v1/user/aboutGET /users/{id}/about
GET /g2/user/followers, /g1/user/followers, /gql/user/followers/chunk, /v2/user/followers, /v1/user/followers/chunkGET /users/{id}/followers
GET /g2/user/following, /g1/user/following, /gql/user/following/chunk, /v2/user/following, /v1/user/following/chunkGET /users/{id}/following
GET /gql/user/medias, /g2/user/medias, /v1/user/medias/chunk, /v1/user/medias/pinnedGET /users/{id}/posts — pinned posts included
GET /v2/user/clips, /gql/user/clips, /v1/user/clips/chunk, /v1/user/videosGET /users/{id}/reels
GET /v2/user/tag/medias, /v1/user/tag/medias/chunkGET /users/{id}/tagged
GET /gql/user/repostsGET /users/{id}/reposts
GET /v2/user/stories, /v1/user/stories, and their /by/username variantsGET /users/{id}/stories
GET /v2/user/highlights, /v1/user/highlights, and their /by/username variantsGET /users/{id}/highlights

Posts and media

HikerAPIherascrape
GET /v2/media/info/by/id, /v1/media/by/id, /v2/media/by/id, /v1/media/userGET /posts/{id}
GET /v2/media/info/by/code, /v1/media/by/code, /v2/media/by/codeGET /posts/{id} — pass the shortcode
GET /v2/media/info/by/url, /v1/media/by/url, /v2/media/by/urlGET /posts/{id} — pass the shortcode from the URL
GET /v2/media/comments, /v1/media/comments/chunk, /gql/comments, /gql/comments/chunkGET /posts/{id}/comments?user_id= — the post owner's id
GET /v2/media/likers, /v3/media/likers, /v1/media/likers, /gql/media/likersGET /posts/{id}/likers?user_id= — the post owner's id
GET /gql/media/usertagsGET /posts/{id} — usertags is on the post
GET /gql/media/clips_metadataGET /posts/{id} — clips_metadata is on the post
GET /v2/media/comments/infosGET /posts/{id} — the counts are on the post
GET /v1/media/download/photo, /v1/media/download/video, …/by/urlGET /posts/{id} — file URLs are in image_versions2 / video_versions
GET /v1/media/oembedGET /oembed?url=
GET /v1/media/pk/from/code, /v1/media/code/from/pkGET /resolve/media — free
GET /v1/share/by/url, /v1/share/by/code, /v1/media/pk/from/urlGET /oembed?url=

Batch ?media_ids= endpoints have no equivalent. The slices they returned — usertags, clips metadata, comment counts — already live inside a single GET /posts/{id}, so we did not reproduce them. If you batched to read one slice across many posts cheaply, each post is now its own request. At $0.0004 that is usually still cheaper; check the arithmetic for your volume.

Comments

HikerAPIherascrape
GET /v2/media/comments/replies, /gql/comments/threaded, /gql/comments/threaded/chunkGET /comments/{id}/replies — media_id and user_id required
GET /gql/comment/likers, /gql/comment/likers/chunkGET /comments/{id}/likers
HikerAPIherascrape
GET /v3/fbsearch/accounts, /v2/fbsearch/accounts, /v1/search/users, /v2/search/accountsGET /search/users
GET /v2/search/hashtags, /v1/search/hashtags, /v1/fbsearch/topsearch/hashtagsGET /search/hashtags
GET /v3/fbsearch/places, /v2/fbsearch/places, /v1/fbsearch/places, /v2/search/placesGET /search/places
GET /v2/search/music, /v1/search/musicGET /search/audio
GET /v2/fbsearch/topsearch, /gql/topsearch, /v1/fbsearch/topsearch, /v3/fbsearch/topsearchGET /search/top

Hashtags, locations, audio, stories, highlights

HikerAPIherascrape
GET /v2/hashtag/by/name, /v1/hashtag/by/nameGET /hashtags/{name}
GET /v2/hashtag/medias/top, /v1/hashtag/medias/top/chunkGET /hashtags/{name}/top
GET /v2/hashtag/medias/recent, /v1/hashtag/medias/recentGET /hashtags/{name}/recent
GET /v1/hashtag/medias/clips/chunk, /v2/hashtag/medias/clipsGET /hashtags/{name}/reels
GET /v1/location/by/idGET /locations/{id}
GET /v1/location/medias/top, …/top/chunkGET /locations/{id}/top
GET /v1/location/medias/recent, …/recent/chunkGET /locations/{id}/recent
GET /v1/location/searchGET /search/places?lat=&lng=
GET /v2/track/by/idGET /audio/{id}
GET /v2/highlight/by/id, /v1/highlight/by/idGET /highlights/{id}
GET /v1/highlight/by/urlGET /oembed?url= for the reel_id, then GET /highlights/{id}
GET /v2/story/by/url, /v1/story/by/urlGET /oembed?url= for the reel_id, then GET /stories/{reel_id}
GET /v1/story/download, …/by/url, …/by/story/urlGET /stories/{reel_id} — file URLs are on each item
GET /sys/balanceGET /system/balance — free

What we do not have

Honest list, so you find out here rather than in production.

Instagram removed these, so nobody has them. Nothing to migrate to.

  • GET /v1/location/search as a standalone geo search. The venue picker at /search/places covers the common case.

Returns different data than you expect.

  • GET /v2/story/by/id, /v1/story/by/id — we have no fetch-one-story-by-id endpoint. GET /stories/{reel_id} takes the owner's user id and returns their whole active reel. Fetch that and match on the item's pk.

Not implemented. If one of these blocks your migration, tell us — several are small, and we prioritise by what migrating customers actually need.

HikerAPINotes
GET /v2/user/suggested/profiles, /v2/user/explore/businesses/by/id, /gql/user/related/profilesRelated-profile suggestions.
GET /v1/user/guides, /v1/location/guidesGuides.
GET /v2/media/templateMedia share template.
GET /v1/media/insightOwner-only insights; needs the account to own the post.
GET /v2/media/comment/offensiveOffensive-text check.
GET /v2/fbsearch/reels, /v2/search/reels, /v3/fbsearch/reelsReels search. /search/top and /hashtags/{name}/reels cover much of it.
GET /v2/track/by/canonical/id, /v2/track/stream/by/idCanonical-id lookup and stream URL.

Before and after

- GET https://api.hikerapi.com/v2/user/followers?user_id=25025320&page_id=ABC
- x-access-key: <key>
+ GET https://api.herascrape.com/users/25025320/followers?cursor=ABC
+ x-api-key: <key>
- GET https://api.hikerapi.com/v2/media/info/by/code?code=B4XpqViUFUI&safe_int=true
+ GET https://api.herascrape.com/posts/B4XpqViUFUI
- GET https://api.hikerapi.com/v2/user/by/username?username=instagram
- GET https://api.hikerapi.com/v2/user/stories/by/username?username=instagram
+ GET https://api.herascrape.com/users/username/instagram   # returns pk, cache it
+ GET https://api.herascrape.com/users/25025320/stories

Agent prompt

Paste this into your coding agent and point it at your repository. It fetches the docs it needs, so you do not have to attach anything.

You are migrating this codebase from HikerAPI (api.hikerapi.com) to
herascrape (api.herascrape.com).

First, read these — they are the source of truth, and this prompt alone is not
enough to do the migration correctly:

- https://herascrape.com/docs/llms-full.txt
  The complete herascrape documentation as one plain-text file: every endpoint,
  the pagination and error contracts, and the full HikerAPI translation tables.
- https://herascrape.com/docs/guides/hikerapi-migration
  The migration guide on its own, if you want just the tables.
- https://api.herascrape.com/openapi.json
  The OpenAPI (Swagger) schema, emitted by the running service. Authoritative
  for paths and parameters; use the "What comes back" examples in the docs for
  response field names.

Then, across the whole repo:

1. Replace the base URL https://api.hikerapi.com with
   https://api.herascrape.com.
2. Rename the auth header `x-access-key` to `x-api-key`. Keep the value in
   its existing environment variable.
3. Rewrite every request path using the "Endpoint translation" tables. Many
   HikerAPI paths collapse onto one of ours — pick the matching row.
4. Users are addressed by numeric id (/users/{id}). The only username path is
   GET /users/username/{username}, which returns the profile including `pk`.
   Where the code called a by-username sub-resource (stories, highlights,
   followers), resolve the username once, cache the id, then call the
   id-based endpoint. Flag any place where caching is not straightforward.
5. Posts: replace by-id, by-code and by-url calls with GET /posts/{id}, which
   accepts either the media pk or the shortcode. Extract the shortcode from
   any instagram.com/p/<code>/ URL.
6. Replace all pagination parameters (page_id, next_page_id, max_id,
   next_max_id, min_id, end_cursor, page_token, reels_max_id,
   profile_grid_items_cursor, repost_next_max_id) with a single `cursor`.
   Read the next token from `next_cursor` and loop while `has_more` is true.
   Two exceptions: /posts/{id}/comments pages on `min_id` (branch on
   `has_more`), and /users/{id}/posts pages on `cursor` taken from
   `feed.profile_grid_items_cursor`.
7. Delete these parameters: safe_int, flat, force, amount, rank_token,
   expand_suggestion, can_support_threading.
8. List responses are wrapped in {items, next_cursor, has_more}. Where the
   old code read a bare array, read `items`. Object fields are otherwise
   unchanged — both APIs return Instagram's JSON.
9. Respect the rate limit: 10 requests/second per key. If the code fans out
   concurrently, cap it.
10. Do NOT invent endpoints. If a call maps to something in the "What we do
    not have" section of the migration guide, leave it in place and mark it
    with a TODO naming the limitation. Do the same for any field you cannot
    confidently map. Never guess a path that is not in the translation tables.

Produce a summary of every call site changed, plus the list of TODOs.

If your agent cannot fetch URLs, download llms-full.txt and attach it — it is the whole of these docs in one file.

Getting started

Free balance to trial the migration, no card required, and cheaper per call across the board. Stuck on a mapping or an endpoint you do not see here? Get in touch — we will map it, or build it.

On this page