# Changelog of Instagram Comments Scraper — Scrape Instagram Comments, Replies (`steadyfetch/instagram-comments-scraper`) Actor

- **URL**: https://apify.com/steadyfetch/instagram-comments-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/steadyfetch/instagram-comments-scraper.md

## Changelog

### 1.0.46 — 2026-10-17

- **A Meta Graph API media id is now named as one.** A bare number of 17 or 18 digits that starts with 17 or 18 is the shape of an id from Meta's Graph API, not of an Instagram post. It was already turned away before any lookup, with a sentence about account handles; its uncharged row now says what it looks like and asks for the post's own link (instagram.com/p/CODE/ or /reel/CODE/) — if it really is an Instagram post, its link works too. Which rows are charged, the input fields and the output columns are unchanged.

### 1.0.45 — 2026-10-16

- **The run summary uses plain names.** The run's summary — the last dataset row and the OUTPUT record — now names the count of reads the run made `reads`. The counts themselves, which rows are delivered, the input fields and every other column are unchanged.

### 1.0.44 — 2026-10-16

- **A run that finds only comments you already have now says "nothing new" on the run page, with what to do next.** Each row already said so. The run's status line now says too: "Nothing new since your last run", with the two ways forward — turn on "Include comments you already have" to collect them again, or run again once new comments arrive. Before, it either gave no next step or, beside a few comments past the end of the post, said Instagram had returned everything it has, which read as if the post had nothing.
- Nothing else changes: the same rows, the same charges, the same input fields and output columns.

### 1.0.43 — 2026-10-12

- **New: one post's comments from one web request.** Besides running the actor as before, you can now send one Instagram post link to the actor's endpoint — GET or POST to the address on its Endpoints tab, with `postUrl` and optionally `maxComments` (100 if you leave it out) and `includeReplies` — and get that post's comments and replies back as JSON in the same response, with no run to start and no dataset to read. Each comment returned has the same fields as a row in a run's dataset. You are charged per comment returned, at the same per-comment price as a run, and a reply costs the same as a comment; a request that returns no comments is not charged, and if the charge for a request cannot be completed, its comments are not sent and nothing is charged. One request returns at most 500 comments, and 50 on the Apify free plan, where the endpoint also has a shared hourly and daily limit. The endpoint does not skip comments your account already has: every request returns the comments it reads.
- Running the actor works exactly as before: nothing changes about the price, which rows are charged, the input fields or the output columns.

### 1.0.42 — 2026-10-11

- **Clearer wording when a run stops at its limit.** Rows for the posts a run could not finish now carry the status "limit_reached" and say "This run reached its limit", with how to fetch the remaining comments in a new run, and the run page counts them as "past this run's limit" instead of printing an internal word. Nothing changes about the price, which rows are charged, the input fields or the other output columns.

### 1.0.41 — 2026-10-08

- **The monthly data allowance behind this actor was raised, so a busy month no longer stops delivery part-way through.** Nothing you are charged changes: the allowance is ours, not yours, and a run that ever meets it still stops honestly and charges nothing for what it did not deliver.

### 1.0.40 — 2026-10-06

- **Comments are now saved to your dataset a page at a time instead of one at a time, so a big run gets further before its time limit.** Saving and charging each comment and reply separately took a large share of the run's time. The comments, their order (each reply still right after its comment), what each row contains and which ones are charged are exactly as before, and nothing is charged until its rows are in your dataset.
- Nothing changes about the price, which comments are charged, the input fields or the output columns.

### 1.0.39 — 2026-10-03

- **The help now says what running the same posts again does.** The input form's description and the post links field say it plainly: comments your account already has are skipped and not charged, and the run reads on past them to the ones you do not have yet — a higher "Max comments per post" reads further down the list. The "How often this data changes" section says the same and suggests a schedule: daily for a post in its first week, weekly after that. Nothing changes about the price, which comments are charged, the input fields or the output columns.

### 1.0.38 — 2026-10-03

- **A stop now says which limit really ended the run.** When the actor's own limit for a small ask stopped it from reading another page of comments, the run page and the uncharged rows said "your maximum cost per run was reached", though your maximum still had room; they now say it was the actor's own limit and that a bigger "Max comments per post" reads further. And a run whose maximum cost per run left no room for even one comment now says it stopped before any charge, instead of "stopped at your maximum cost per run". Nothing changes about the price, which comments are charged, the input fields or the output columns.

### 1.0.37 — 2026-10-03

- **Comments below the ones you already have can now be reached.** A run that met only comments your account already has stopped after three pages, so once you held the top 45 or so comments of a post, no run could reach the comments below them — the same three pages were read and skipped every time. How far a run now reads past comments you already have grows with the number of comments you ask for on each post: at least three pages, and more for a bigger ask, so a higher per-post limit reaches further down the list. The comments it finds there are delivered and charged exactly as before, one comment at a time; comments you already have are still skipped and not charged; and a post whose comments you hold as far as your ask can reach still ends on one uncharged row, which now names the per-post limit as the way to read further. A reply thread under a comment you already have is looked at no more than twice per run. Nothing changes about the price, which rows are charged, the input fields or the output columns.

### 1.0.36 — 2026-09-27

- **Asking again for a post whose top comments you already have is quicker and reads less.** When a run finds that the top of a post's comment list is all comments your account already has, it now remembers that, so the next run on the same post — while its published comment count is unchanged — stops after the first page instead of reading two more pages of comments you already hold. The answer is the same as before: nothing new delivered, nothing charged, one uncharged row saying so, and "Include comments you already have" still collects them again. A run that skipped comments only because they were in a dataset you pointed it at no longer leaves this note behind, so a later run without that dataset still delivers them.
- **A bare word in "Post URLs" is no longer read as a post code.** A value with no capital letter and no hyphen — `natgeo`, `@natgeo` or a number — could be an account's handle, and was being read as a code for a different post. It now gets one uncharged row saying it does not read as a post code, and pointing to our Instagram Profile Posts Scraper for an account's posts, or to pasting the post's link for one post. Post links and real post codes are read exactly as before. Nothing changes about the price, which rows are charged, the input fields or the output columns.

### 1.0.35 — 2026-09-26

- **A post link with its address shortened now works.** A path pasted with no instagram.com in front of it (`/p/<code>/`), an `instagr.am` short link, and a post code copied with a trailing slash are now each read as the post they name: the same post, the same price, and its comments charged exactly as the full link's would be. Until now each came back as an uncharged row saying it was not a post link. Nothing changes about the price, which rows are charged, the input fields or the output columns.

### 1.0.34 — 2026-09-26

- **A run on the Apify free plan now says which price it was charged at.** When a run is billed at the Apify free plan's price, the run page now says so in one sentence — $2.40 per 1,000 comments — and names what the same run costs on paid plans: $1.40 on Bronze, $0.90 on Silver and $0.60 from Gold. Runs on paid plans read exactly as before. A run stopped at the free plan's daily limit whose token could not update the repeat memory now fits its whole summary on the run page instead of being cut off at the end. Nothing changes about the price, which rows are charged, the input fields or the output columns.

### 1.0.33 — 2026-09-26

- **A run cut off before it finishes is now accounted for.** The run now notes its own start in its internal record, so a run that ends without finishing — a hard abort, a crash or a timeout — is still accounted for on our side. Nothing changes about what is delivered, which rows are charged, the price, the input fields or the output columns.

### 1.0.32 — 2026-09-26

- **A deep comment run on a paid Apify plan is no longer cut short by this actor's own per-run data budget, and a run that does reach it now says so truthfully.** On paid plans that budget now grows with the number of comments you ask for, so thousands of comments across several posts are collected in one run. When a run does stop at it, the uncharged rows and the run page now say that a new run on the same links continues, skipping comments you already have, instead of saying the stop lasts until the start of next month. Nothing changes about the price, which comments are charged, the input fields or the output columns.

### 1.0.31 — 2026-09-24

- **A daily allowance on the Apify free plan.** On the free plan this actor now makes at most 30 pages of comments per account in any 24 hours (a reply thread counts as one page), and accounts on that plan share one daily allowance on this actor. Past either, the run keeps every comment it already delivered, adds one uncharged row saying how many comments were not collected and when the allowance resets (UTC), says the same on the run page, and charges nothing past it. Paid Apify plans carry no daily allowance and are unchanged. No price, input field or output column changed.

### 1.0.30 — 2026-09-24

- **Settings sent wrapped in an extra "input" object are now read.** A run whose input arrives as `{"input": {…}}` — for example from `run_input={"input": {...}}` in the Python client — now reads those settings as if sent directly and adds one uncharged note row naming them. Before, the run stopped with a guidance row and collected nothing. Nothing changes about the price, the input fields or the output columns.

### 1.0.29 — 2026-09-24

- **Comments you already have are no longer counted as comments the post does not have.** When a post runs out of comments before your ask is filled, only the part of the ask beyond the post's own comments is reported as not available; the comments of that post already in your account are reported as skipped, and the row says how many. This holds on a post read to its end on this run and on one an earlier run already read to its end.
- **Runs that deliver many comments finish sooner.** Your account's record of delivered comments is now saved once per page of comments instead of once per comment; which comments are skipped next time is unchanged.
- **A run that Apify restarts after it has already delivered keeps its own record of that delivery.** If the restarted part of a run delivers nothing new, the run's internal record now keeps what the earlier part delivered and charged, with a note of the restart, instead of being rewritten as if nothing had been delivered; one line in the run log says so. Nothing changes about what is delivered, which rows are charged, the price, the input fields or the output columns.

### 1.0.28 — 2026-09-23

- **The post links field is no longer marked required in the input form, and its help now opens with what to pass and an example.** An AI agent or an API call that leaves it out gets the built-in sample rows, exactly as a bare Start always did; the help says so plainly instead of calling the field required.
- **The top of this page now says how often comments change and how to schedule a rerun** — save the input as a task, add it to a schedule, and comments this account already received are skipped and not charged again. Nothing changes about what is delivered, which comments are charged, the price, the input fields, the output columns or the charged event.

### 1.0.27 — 2026-09-22

- **The run log no longer prints an internal usage summary at the end of a run, and a failed internal bookkeeping write no longer prints where it was being saved.** Nothing changes about what is delivered, which rows are charged, the price, the input fields or the output columns.

### 1.0.26 — 2026-09-22

- **The run log no longer prints internal cost lines, and a row stopped by this actor's own monthly collection allowance no longer quotes a dollar figure.** Those numbers described our own costs with the data source, not anything you pay. The row still says the allowance was reached and that it resets at the start of each month; your rows and charges are unchanged.

### 1.0.25 — 2026-09-22

- **When the data source itself has an outage, the run now says the comments could not be read this time and asks you to try again, instead of reporting the post as permanently unavailable.** Some answers from the source are a real verdict about the post you sent — a bad address, a private account, a post that no longer exists — and those are final, so the run says so and moves on. Everything else is the source having a bad moment: rate limiting, a server error, a dropped line, or the source's own origin being unreachable. Until this build the run had a fixed list of the moments it recognised as temporary, and anything not on that list was reported as final. On 22 September the source's origin went down for about half an hour and answered with a code that was not on that list, so posts it had served fifteen minutes earlier came back marked permanently unavailable. That is now the other way round: only the answers that are genuinely a verdict about your post are final, and anything else is treated as temporary, is not charged, and asks you to run it again. Final answers behave exactly as they did. Nothing changes about what is delivered, which comments are charged, the price, the input fields or the output columns.

- **An answer the data source has never sent before now counts as an outage rather than as something we paid for.** The run keeps its own record of which of the source's answers cost us money, and until this build that record was a fixed list — so a response nobody had listed, such as a code the source first sent during an outage, was read as one we had bought. Now only the answers the source actually bills count as bought; everything else is booked at nothing and simply tried again. Nothing changes about what is delivered, what you are charged, the price, the input fields or the output columns.

### 1.0.24 — 2026-09-20

- **A run started with field names this actor does not have now reads the first three of them on the run page and counts the rest — "and 37 more" — instead of listing every one, so most of those runs keep the names on the line instead of losing them.** Apify cuts a run's status line at 500 characters, and that list was the one part of the line whose length was the caller's rather than ours: forty unknown names composed a sentence of 1,026 characters on their own, and eight were already enough to push the line past the cut. Since 1.0.23 the line stayed inside the cut by giving that whole sentence up and pointing at the uncharged row instead — correct, but it meant a caller who sent eight names read none of them on the run page. The sentence now carries a ceiling of its own, so on an ordinary run the names ride the line together with what was delivered, what was charged and what to do next. A name longer than 40 characters is shown to its first 39 and marked, and where a sentence still cannot fit, the shorter one takes over exactly as it does today. The uncharged row in your dataset still names every field you sent, in full, as it always did. Nothing changes about what is delivered, which comments are charged, the price, the input fields or the output columns.

### 1.0.23 — 2026-09-20

- **When a run is started with field names this actor does not have, the run page now says so in a sentence of a fixed length instead of listing every one of them and running off the end of the page.** Apify cuts a run's status line at 500 characters and shows "..." for the rest. This actor's line names the fields a caller set that it does not recognise, so the length of that sentence was the CALLER'S rather than ours: a template or an agent that fills a whole generic form sends eight unknown names or more, and eight already pushed the line past the cut — with the part the platform threw away being the sentence that says what was and was not charged, and on a run whose account memory could not be updated, the sentence saying the comments delivered now will be charged again next time. Where the names fit, they are still all there, exactly as before. Where they do not, the line now says "This run set fields this actor does not have — it reads "Post URLs" (`postUrls`), and the uncharged row above names them.", and the uncharged row in the dataset carries every name in full, as it always did. Nothing changes about what is delivered, which comments are charged, the price, the input fields or the output columns.

### 1.0.22 — 2026-09-19

- **The monthly allowance behind this actor's data reads has been raised again — a busy month no longer stops delivery part-way through.** Nothing you are charged changes: the allowance is ours, not yours, and a run that ever meets it still stops honestly and charges nothing for what it did not deliver.

### 1.0.21 — 2026-09-19

- **The whole "Maximum cost per run" you set is now spent on comments; before this build the run held back about a twelfth of it.** Your cap pays for comments and nothing else — the compute, the proxy and the data behind the run are ours, not yours — but the run was still reserving roughly 8% of your cap against those costs before it planned a single comment. So a cap worth ten comments bought nine, and the tenth was money you had authorised and could not spend. That reserve is gone. A run at its cap still ends the same honest way it always did: it stops itself, tells you what it cut and why, and charges you for nothing it did not deliver. No price, input field, output column or charged event changed.

### 1.0.20 — 2026-09-19

- **A post whose last page was only part-read is no longer remembered as read to its end.** Three things can leave the last page of a post's comments part-read: your maximum cost per run, your run clock, or the number of comments you asked for being reached part-way down it. When any of them landed on a page Instagram offered no continuation for, the run treated that as the post having nothing more to give — its row said so over comments the limit had cut, and since 1.0.19 it also wrote the post down as fully read at its published count. A later run on the same post would then read one page, find only comments you already had, see the count unchanged, and tell you it held them all — while the comments past the cut had never been delivered. A run stopped by one of your limits now reports that limit on the same uncharged row every other limited run gets, and a run whose ask filled part-way down a page remembers nothing about that post's end; the next run collects the rest as ordinary new comments, charged as usual, and only a run that reads the whole of the last page records the end. A run continuing after Apify moved it to another server also no longer records an end it did not see from the top. No price, input field, output column or charged event changed.

### 1.0.19 — 2026-09-19

- **Running the same post again no longer buys pages of comments you already have.** When a run reads a post all the way to the end of what Instagram serves for it, that is now remembered in your account's own memory, together with the post's published comment count at the time. A later run on the same post still reads its first page — that page is what says whether anything has been added — and where it holds only comments you already have AND the post's published count has not moved since, the run stops there instead of buying the pages below it. Measured on a post of 60 comments already collected: three reads on every repeat, now one. The row says exactly that: it names the day the post was read to its end, the published count it is unchanged from, how many comments on that first page you already had, and that the rest carried no result fee — and it now carries Instagram's own answer about the post rather than one of this actor's own bounds. The moment that count rises, the run goes and collects what is new; **Include comments you already have** reads the whole post again whatever the memory says; and a run that cannot open the memory behaves exactly as before. No price, input field, output column or charged event changed.

- **A post whose published comment count comes back blank is no longer read as a post with nobody commenting.** That count is what this actor uses to tell "this post really has none" apart from "that read did not come through", and a blank value was being counted as a zero. A blank is now treated as a count that could not be read: the run says the read was unavailable and worth running again, instead of handing you a definitive "nobody has commented yet", and it no longer leaves a post early when the post still had pages to give. A post that really does publish a zero is unchanged, and nothing about charging moved.

### 1.0.18 — 2026-09-19

- **A run that gets moved to another server part-way through now reports what the whole run delivered, and still finishes the result limit you asked for.** Long jobs are sometimes moved between servers while they run. The comments already collected were always kept, and never collected or charged a second time — that part was right. What was wrong was everything the run then said about itself: the summary counted only the comments collected after the move, so it could read "0 delivered" next to comments you had already been charged for; a row appeared saying the comments asked for on a link were not delivered when most of them already had been; and the run could give up part-way back through its own already-collected comments and stop short of your limit. All three are fixed. The run now counts everything the whole run delivered, reports only the comments that really are still owed, and carries on from where it had reached instead of re-reading its way back to it. Nothing about the result limit, the price, the input fields, the output columns or the charged event changed, and only delivered comments carry a result fee.

### 1.0.17 — 2026-09-18

- **The monthly allowance behind this actor's data reads has been raised — a busy month no longer stops delivery part-way through.** Nothing you are charged changes: the allowance is ours, not yours, and a run that ever meets it still stops honestly and charges nothing for what it did not deliver.

### 1.0.16 — 2026-09-18

- **When the run page's one-line summary is too long to fit, the sentences about what you were charged are now the last to go, not the first.** Apify cuts that line at 500 characters, so a long run drops clauses until it fits — and the order it dropped them in was wrong: "the comments you already had were skipped, not charged", "none of the undelivered rows was charged" and the note about a repeat check that could not run were being thrown away to make room for a reply-thread note and a request to open a support issue. Measured across 1,440 shapes a real run can end in, 801 of them lost a sentence about money or lost the one sentence telling you what to do next, while the line still read as a tidy 500 characters. Everything that costs you nothing to lose now gives way first — the census of undelivered rows folds to a pointer, the reply note, the cap note and the support ask go, then the stop's own guidance, which the receipt row carries in full — and only under all of that do the money sentences shorten to their plainest form. They never disappear. Nothing about what is collected or charged changed.

### 1.0.15 — 2026-09-16

- **Comments that end early are now reported as the end of the post's comment list, never as a temporary outage asking you to run it again.** When Instagram serves a page of comments for a post and then answers "nothing there" for the page it just pointed us at, that is how this feed ends a list: the same answer comes back on every re-ask, and the page it points at never exists. Until now that was read as the source going quiet for a moment — the row said it was temporary and asked you to re-run, and the re-run met the identical answer and, with **Include comments you already have** switched on, charged you a second time for the comments you already had. Those rows now say what is true: the comments you were given are everything Instagram returned for that post, there is no result fee for the rest, and no re-run is asked for. A post that answers nothing on its FIRST page is unchanged — there it really is a wrong link, a private account or a deleted post, and the row still says so.

- **And a run no longer buys the empty page at the end.** Where the last page came back short, Instagram's own answer says it has no more, and the post's own published comment count agrees that at most one page is outstanding, the run stops there instead of paying for a read that comes back with nothing — on the run that found this, 7 of the 11 posts each bought one. Where any of those three disagree — a full page, a feed that says it has more, or a post whose own count says many comments are still to come — the run follows the page exactly as before and collects what is there. No price, no input field, no output column and no charged event changed, and only delivered comments carry a result fee.

### 1.0.14 — 2026-09-16

- **A run your own "Max run seconds" ended no longer tells you the data source was unavailable.** The read that is running when your limit arrives is cut off by this actor's own timer — that is what keeps a run inside the limit you set. Until now that cut looked exactly like the source going quiet: the comments still to collect were booked against the source, the row said it was unavailable and asked you to run it again, and the re-run met the same limit and said the same thing. The read now says whose timer stopped it, so a run your limit ended is booked as your run time limit, names "Max run seconds" as the setting to raise, and is not asked again on our side inside the same run. A real outage or rate limit on the source reads exactly as it did, is still waited out, and is still worth a re-run. Comments already collected are delivered and charged as before, and the cut ones are still uncharged.

### 1.0.13 — 2026-09-16

- **A post that stops answering part-way is no longer reported as deleted.** When Instagram served a page of comments for a post and then answered 404 on the next page, the whole post was booked as "Instagram has nothing at post X — the link is wrong, the account is private, or the post was deleted", which is permanent and tells you to stop asking. A post that has just served comments is not gone; that answer is the feed going dark for a moment, and a re-run usually gets the rest. Those rows now say the read was temporary and ask you to re-run, exactly as any other unread page does, and nothing is charged for them. A 404 on the FIRST page of a post is unchanged — there the feed is the only evidence there is, and the post really is gone.

- **A post proved to have no comments is not bought twice in the same hour.** When a post's own published comment count is zero, that answer is now remembered in your account's own memory for a short window, and a run that asks for the same post again inside it is handed the same honest, uncharged row without a new read being bought. The row says so: it names how long ago the read happened and that this run did not repeat it. The window is deliberately short — an empty post can gain a comment at any moment, so this is never yesterday's answer, and a run outside the window reads the post again. Turning "Include comments you already have" on also reads it again. Nothing about money moved for you: the same row, still uncharged, and no price, input field, output column or charged event changed.

### 1.0.12 — 2026-09-15

- **"Max run seconds" is now the limit, not a number the run could pass.** The run's clock decided when a page could be *started* and nothing decided how long one could *take*: a page begun with seconds left on your limit was still allowed its own 25-second read, and two more after it, so one slow answer from Instagram could carry the run past the number you typed with nothing able to end it — the comments were still written out and the page still said the clock stopped it, but the run itself kept going. Every read is now bounded by the smaller of its own timeout and what your run actually has left, so a run stops inside its limit whatever the feed does, and the comments the clock cut are written out as uncharged rows naming the setting to raise. The same change fixes a run the platform restarts part-way through: it now finishes inside the window you bought instead of starting that window again from zero. Nothing else moved — no price, no input field, no output column and no charged event changed, and a run with time to spare still gives every read its full patience.

### 1.0.11 — 2026-09-14

- **An Instagram "share" link no longer collects a different post's comments and bills you for them.** Instagram's Share button hands you an address like `instagram.com/share/p/BAgXyZ12345` — the token on the end is a redirect, not the post's own code. This actor read the `p` in that address as the post marker and took the redirect token as the code, which decodes to a real post: somebody else's. The run then collected that stranger's comments, charged for every one of them, and wrote the post link on each row back as `instagram.com/p/<the redirect token>/` — so the rows looked like the post you had asked for and there was no way to tell. A share link is now refused before anything is read: one uncharged row that says what the link is, why its token is not the post code, and the one move that fixes it — open it in a browser, copy the address it lands on, paste that into "Post URLs" and press Start. Nothing is bought for it and there is no result fee.

- **And four more addresses that were being read as posts are refused the same way.** The fault was not the share link, it was how the address was read: this actor looked for `p`, `reel`, `reels` or `tv` **anywhere** in the path, and checked the site by looking for "instagram.com" anywhere in the text you pasted. So `instagram.com/reels/audio/1234567890/` — Instagram's page for one sound — was read as a reel with the code "audio" and collected a post nobody had asked for; a direct-message address and any deep path with one of those four words in it did the same; and a look-alike address such as `instagram.com.example.net/p/CODE/` or `myinstagram.com/p/CODE/` was accepted as Instagram. The post marker is now only read where Instagram actually puts it — at the start of the path, or straight after the account handle — and the site is read as the address's own host. Every real post, reel, IGTV and `/<handle>/p/CODE/` link still works exactly as before, an upper-cased link now works too, and a link that cannot be read is one uncharged row naming the field and the shape that works. No price, no input field, no output column and no charged event changed.

### 1.0.10 — 2026-09-14

- **A run that brings back no comments now tells you what to do about it — and counts the mistake it never showed.** A run that delivered nothing used to name only the count and a reason code — "Delivered 0 comments of 1 asked for across 1 post. Not delivered: 1 not found" — and stop there, with no next step, because the run had ended cleanly and only a run stopped by a limit ever said anything further. Each reason now carries its own plain sentence: a link Instagram has nothing at tells you to open it in a browser and says a re-run returns the same answer, a post that really has no comments yet says so, a temporary read says to start the run again, an answer this actor could not map says it is ours rather than yours and asks you to open an issue, and the monthly collection allowance says it is ours and resets at the start of the month. **And a value this actor could not read is now counted on that line at all**: it was named on its own uncharged row but was missing from the run page's summary entirely, so a run whose only link was a profile address said "Delivered 0 comments of 1 asked for across 1 post." and nothing else. It now names the count and tells you which field to paste post links into and what one looks like. A run that did deliver comments is unchanged and says nothing extra.

- **What a run costs, and whether the same links tomorrow are worth it, are now on the first screen.** You had to scroll past the column table and the sample row to learn that a comment is **$0.60 per 1,000** on Gold and above ($2.40 per 1,000 on the Apify free plan) and that a reply is charged on that same event at that same price. The re-run advice was further down: comments keep arriving for days after a post goes up and the busiest hours are the first few, so the useful pattern is the same links again tomorrow — and the ones you already have are skipped rather than charged again, so a daily watch pays only for what is new. Both now sit in the opening block beside the actor id and the input. No price, no input field, no output column and no charged event changed.

### 1.0.9 — 2026-09-14

- **A run that can read your repeat memory but not write to it now says so, instead of letting your next run pay for everything twice.** The previous entry covered a token that cannot OPEN that memory. This is the other half: an API token can be allowed to read key-value stores and not to write them — or to write them and not to create one you do not have yet — and such a run opens your memory, recognises every comment you already had correctly, and then remembers nothing it delivered. The run looks perfect and your NEXT run is charged for the whole delivery all over again. The run page now names it the moment the first write is refused, an uncharged row at the top of the dataset carries the cause and the fix in full, the receipt carries `repeatWrite: "denied_scope"`, and the run log keeps Apify's own message and adds the permission to grant: key-value store **Write** (and **Create**), or Actor runs set to **Full access**, under Settings → API & Integrations. A write that fails for an ordinary reason is still just retried bookkeeping and says nothing. Both run-page sentences are also shorter and now read the same on every actor in the portfolio, with the whole fix on the row. No price, no input field, no delivered column and no charged event changed.

- **A run that set a field this actor does not have now reads as one sentence on the run page.** The sentence naming the field you set and the field this actor reads carried a semicolon, which is the character the run page uses to separate one statement from the next — so anything reading that line saw two half-sentences instead of one. Same words, clearer line. Nothing about what is collected or charged changed.

- **A run that cannot open your account's repeat memory now says so instead of quietly charging you twice.** This actor promises you never pay for the same comment twice: it remembers what it delivered to your account in a key-value store there, and skips those next time — which is the whole point of watching the same posts daily. A run started from the API with a **scoped token** in restricted-access mode cannot open that store unless the token is allowed to — so the check never ran, every comment you already had was collected and charged again, and nothing on the run page, the rows or the receipt said a word about it. The run page now names the cause and the fix, an uncharged row at the top of the dataset says the same thing for anything reading rows rather than the page, the receipt carries `repeatCheck: "unavailable_scope"`, and the run log keeps Apify's own message and adds the permission to grant: key-value store **Read, Write and Create**, or Actor runs set to **Full access**, under Settings → API & Integrations. Every other reason the memory can be unreadable reads exactly as it did before. No price, no input field, no delivered column and no charged event changed.

### 1.0.8 — 2026-09-13

- **A post link sent under a slightly different field name is now collected instead of ignored.** A run that put its links in `postUrl`, `url`, `urls`, `link`, `links`, `post`, `posts`, `reelUrl`, `reelUrls` or `startUrls` used to collect nothing: Apify passes a field this actor does not declare straight through, so the run looked like a Start with no post set and came back with one uncharged row naming a field you had never filled in. Those names are now read as the field they plainly mean — Apify's own `{"url": …}` Start-URLs shape included — a link sent under both names is collected once and charged once, and one uncharged row tells you which field to use next time so it stops appearing. A field name that matches nothing still gets an uncharged row, and that row now names the field you set as well as the field this actor reads. No price, no input field, no output column and no charged event changed.

- **The store card now says what a comment costs.** The card said what comes back and what is never charged, and named no price at all — so a buyer comparing actors in the search results could not compare this one on price, and had to open the page to find it. It now carries the same headline the page does: from $0.60 per 1,000 comments, the cheapest paid rate on the ladder. The reply rule stays on the card, because a reply charged as a second unit is the thing that surprises a buyer most elsewhere. Nothing else moved: no input field, output column, charged event or price changed.

- **The store card now says how replies actually arrive.** The card sold "comments and their replies" without saying that a run opens reply threads only while its own reply budget lasts: threads are opened one at a time, and once buying another one would cost more than the comments it returns are priced at, the rest are left unopened. That is unchanged behaviour — the page has described it since the actor was listed and every comment row carries `repliesCollected` — but a buyer reading only the card could expect a thread under every comment. The card now says replies open thread by thread until the run's reply budget is spent, and that each comment says whether its thread was opened. Nothing about the run moved: no input field, output column, charged event or price changed, and a reply is still charged at the same price as a top-level comment.

### 1.0.7 — 2026-09-13

- **Your result limit now holds even when Apify moves the run to another server part-way through.** This actor already picks up exactly where it left off after such a move, and it works out how much of your limit is left from the comments it has already delivered — but it was counting only the comments that carried a fee. A comment your account already has comes back delivered and uncharged, and so does every row on a run that cannot be billed at all, so those were invisible to the count: the run believed more of your limit was unspent than really was, and could hand you more comments than you asked for. It now counts every one already delivered to you, whether or not it carried a fee. Nothing about what you are charged moves — a repeat is still delivered without a result fee, and only delivered comments are charged.

### 1.0.6 — 2026-09-13

- **The page now shows you a row before you spend anything, and its first line is the listing's own name.** A new **What a row looks like** section carries one real delivered comment from a live run — text, author, likes, the reply fields and the charge record — and the heading at the top of the page is now the store title instead of a different name for the same product. No price, no input, no output column and no charged event changed.

- **A read that will never work is no longer reported as one that might.** Two different answers used to arrive as `vendor_unavailable`, the row that says "this is temporary — please re-run": a post Instagram refuses to answer for outright, and an answer that arrives in a shape this actor cannot read yet. Neither changes on a re-run, so that row was selling you a second run for exactly the same answer. Each now has its own uncharged row — `source_refused` and `unsupported_shape` — saying what is actually true, what to check, and that a re-run will not change it. A genuine outage still ships as `vendor_unavailable`, still asks for a re-run, and still carries no result fee. No price, no input and no delivered column changes.

- **A run may now wait longer for a slow source before it gives up.** How long a run can keep waiting is sized against what the comments it is still owed are worth, and this build lets that sizing draw on half of the run's own margin instead of a quarter — so a page that is answering slowly gets about twice as long to come back, and a delivery cut short on a slow page is rarer. Everything that bounds the waiting is unchanged: your run-time limit, your result limit and your cost cap still end it on the spot, no run ever waits less than it did before, and a small ask waits exactly as long as it always has. No input, no output column, no charged event and no price changes.

- **The input schema now speaks to an AI agent as well as to a person.** An agent that finds this actor through Apify's MCP server never opens this page — it reads the input schema. So the schema's own description now opens with the call that works, says what one comment costs and what 300 comments come to, repeats that a reply costs the same as a top-level comment, lists what is never charged, says that the result limit is per post, and names the run option that caps the bill. The post links field leads with the value shape and examples, then what is never charged, then where a profile or hashtag link belongs, with the console sample instruction last. No price, no charged event, no input field and no delivered column changes.

### 1.0.5 — 2026-09-12

- **The time a run waits out a quiet source is now sized to what you asked for, instead of being the same fourteen seconds for every run.** Since the last build a post that hit a quiet stretch was waited out twice — a short wait, then a longer one — and then given up on, whether you had asked for three comments on a two-minute run or five hundred on an hour-long one. A big ask on a long run now keeps waiting and reading the same page again, each wait longer than the last, for as long as the comments it is still owed are worth the run time it costs. A small ask waits exactly as long as it did before, so nothing gets slower or dearer; no run ever waits less than it used to; and no run waits past your own run-time limit, your result limit or your cost cap, all of which still end the waiting on the spot. Where the source comes back, the comments behind the pause are delivered and charged exactly as they always were. Where it does not, nothing changes: the comments in hand are yours, the rest carries no result fee, and the row still says a re-run is the fix.

### 1.0.4 — 2026-09-12

- **An answer this actor already paid for is never bought twice.** When the source replies in a shape this build cannot read, waiting and asking again cannot change one byte of it — the run did it anyway, buying the same dead page three times and spending up to fourteen seconds of your run clock on it. From this build only the refusals that cost nothing and clear in seconds are waited out: a rate limit, a server error, a dropped connection, exactly as before. Nothing about what you are charged moves.

- **A post that came back blank is no longer reported as a post with no comments.** A page holding nothing used to be read as Instagram's own final answer — "nobody has commented yet, that is a definitive answer" — even when the post itself says it has thousands of comments. That told you to stop asking on exactly the run where asking again was what would have got you your comments. Now the post's own published comment count decides: where it says zero, the answer stands as the definitive one it is; where it says otherwise, or says nothing at all, the row is marked temporary and asks you to re-run. Either way there was no result fee.

- **An aborted or migrated run now leaves its receipt from the first moment of the run, instead of only after start-up finishes.** The record that says how a run ended was only put in place once the run had finished starting up — reading your input, opening its stores, working out what a previous attempt had already delivered and charged. A run stopped inside that window ended with nothing written about it at all, which mattered most on a re-started run, where the thing not written about was the earlier attempt's work. It is now in place from the run's first moment. Nothing else moved: no input field, output column, event or price changed, and a run that reaches its work behaves exactly as before.

### 1.0.3 — 2026-09-12

A cost build, and the honest-row copy that goes with it.

- **A post no longer ends because Instagram could not be reached for a moment.** When the source went
  quiet part-way through a post's comments, the run used to stop collecting for that post on the spot —
  about five seconds after the first sign of trouble — and report every comment it still owed as not
  delivered. It now waits and reads the same page again: a short wait, then a longer one, spent once per
  post rather than on every page, and only while the run still has the clock for it and none of your own
  limits have been reached. Where the source comes back, the comments behind the pause are delivered
  exactly as they always were. Where it does not, nothing changes at all: the comments already collected
  are yours and charged as marked, the rest carries no result fee, and the row still says a re-run is the
  fix. A post that does not exist, one with comments turned off, and a run that has reached a limit are
  answers, not pauses, and are never waited on.

- **A link in your rows can never carry a network address, whatever form it arrives in.** Every link
  this actor delivers already went through our own URL hygiene before reaching your dataset, and that
  pass had a gap: where an upstream body writes its links with HTML-escaped separators (`&amp;` in
  place of `&`), the address parameter was not recognised by name and could survive into a row. It is
  now removed however the link is written — escaped, plain or legacy separators, upper or lower case,
  and inside a link that wraps another link. Nothing else in a link moves: the expiry, the signature
  and every routing parameter are delivered exactly as they were served, so the links keep working
  exactly as before. No column, no input, no price and no charge changes.

- A run that has reached your maximum cost per run no longer fetches a page of comments it cannot deliver. It stops at the cap exactly as before, and the page it used to fetch first was never charged to you — so nothing about your rows, your charges or your prices changes.

- The uncharged row for a post the run stopped before it ever opened now says so, instead of offering to pick up where it left off on a post it never read.

- **An uncharged row no longer denies a fee for comments you were already charged for, and no longer blames Instagram for one of this actor's own limits.** A post whose comment feed went dark after it had delivered rows used to end on "There was no result fee — please re-run", sitting directly above the rows that were charged; it now opens with how many were delivered and charged, and offers the re-run for the rest. And a post cut by one of this actor's own bounds — at most 400 comment pages for a single post, or three pages in a row holding only comments you already have — used to be reported as "comments are turned off for it, or nobody has commented yet… that is a definitive answer". Those two bounds are ours, the row now says so, and it names the setting that lifts each. Nothing about your columns, your charges or your prices changes.

- **A post cut by one of this actor's own bounds is now recorded as this actor's bound, not as Instagram running out of comments.** The uncharged row for such a post already said so in words; the status on it still read `no_comments`, the same code a post that genuinely has none gets. Those two rows now carry their own statuses — `skipped.page_cap` for the 400-page bound on a single post, `skipped.all_repeat` for the three-pages-of-comments-you-already-have bound — so a run's own record can no longer say Instagram had nothing more over a walk this actor stopped. Every sentence on those rows is unchanged, nothing is charged for them either way, and no price, input or delivered column moves.

- **A limit set higher than this actor's own no longer refuses the run.** "Max comments per post" above 5,000, or a run clock outside 30 seconds to 1 hour, used to be rejected by the platform before the run started — no run, no rows, and nothing to tell you why, which is what a caller arriving with another scraper's numbers hit. From this build the run starts, continues at the nearest limit, and leaves one uncharged row naming what you asked for and what bound it. Your prices, your charges and every column are unchanged.

### 1.0.2 — 2026-09-11

A listing-copy build.

- The store page now carries the plain note that this actor is unofficial and not affiliated with, endorsed by, or sponsored by Instagram or Meta Platforms, Inc., the same line the rest of the Instagram actors carry.
- Internal only: our own record of what a licensed data feed costs us was corrected, and a request that feed rejects is no longer retried — nothing about your rows, your charges or your prices changes.

Nothing about the actor itself changed: the same inputs, the same columns, the same events and the same prices. There is no reason to re-run anything.

### 1.0.1 — first public build

Instagram comments and replies by post URL.

- Paste post, reel or IGTV links (or the bare code at the end of one). Your limit is exact and it is per post: set 200 and you get 200 from each link, or an uncharged row says why not.
- Replies are collected under the comment they answer and charged at the same price as a top-level comment, on the same single `comment` event. Nothing is charged for starting a run.
- Honest uncharged rows for everything not delivered: `post_not_found`, `no_comments`, `stopped_at_limit`, `vendor_unavailable`, `vendor_budget`. A run that delivers nothing still finishes successfully and says why.
- Repeat memory: comments already delivered to your account are skipped on a later run — not delivered again, not charged — and the slot goes to the next new comment, so a daily watch on the same posts costs only what is new.
- Pressing Start with nothing set returns built-in sample rows at no result fee, so the output shape is visible before anything is collected.
