Written by James Britt
On December 5 that year Instagram launched Stories Highlights and the Stories Archive, and a story no longer had to vanish: “Highlights stay on your profile until you remove them.” Every developer since, asked to grab an account’s highlights, meets the same wall. Neither API whose docs I read, Basic Display as documented in 2023 or the Graph API as documented in 2026, returns them.

The request rarely starts with you. Marketing wants the brand’s highlights archived, or a client wants one for a deck, and the reflex is gem search instagram plus a quick scraper. I have written scrapers like that. Here is why the reflex now costs more than it saves.
2010 to 2015: there was a gem for that
The official instagram gem first shipped on November 30, 2010, and rubygems.org still reads “27 versions since November 30, 2010”. A 2016 capture of Instagram’s own developer site lists it as one of two official libraries, beside a Python one.
The last release was 1.1.6, on September 2, 2015. The repository’s last push came on February 28, 2019; it now sits archived under facebookarchive behind a README that opens “This project is not actively maintained.”
2016 to 2018: scrapers bloom and wilt, stories arrive
With the official gem stalled, the scrapers came. instagram_scraper shipped 13 versions in 12 days, February 3 to February 15, 2016, then stopped. ruby-instagram-scraper, “A simple module for requests to Instagram without an API key,” lasted from June 1 to June 2, 2016.
Stories launched on August 2, 2016: “The photos and videos will disappear after 24 hours and won’t appear on your profile grid or in feed.”
insta_scrape (“Restores all deprecated hashtag functionality”) last released on June 27, 2017. instagram-continued, the community fork of the official gem, stopped on September 7, 2017, and is archived too.
Then December 5, 2017. The highlights post also set up the archive: “your stories will automatically save to your archive when they expire,” and “Only you can see your archived stories.” The official API did not grow to match.
On April 4, 2018, it shrank: GET /users/{user-id}/media/recent was on the changelog’s list of endpoints “deprecated immediately”. Reading another user’s media was gone from the official surface.
2018 to 2020: the scraper that survived wants your login
4.1.
That is the instaloader version, released on September 2, 2018, that added –highlights. The Python tool documents it in three sentences: “Also download highlights of each profile that is downloaded. Requires login. Added in version 4.1.” So the highlights option of the scraper that would outlive the Ruby ones needs an Instagram session in your code.
On June 29, 2020, the legacy API went dark: “As of June 29, third-party apps no longer have access to the Legacy API.” Whatever the official gem had wrapped since 2010 stopped answering.
2024: the last consumer API goes
Kit (ConvertKit) shipped an instagram_basic_display gem for Basic Display, the consumer-app API, on January 31, 2020. It was no route to highlights either: the consumer API was not a general Highlights archive.
On September 4, 2024, Meta gave 90 days’ notice: “After December 4th, 2024, there will no longer be a set of Instagram APIs for consumer developer apps.”
Kit’s gem made its last release, 0.2.3, on November 26, 2024, after a final commit titled “Update code to access token exchange URL to one from docs”. That was 8 days before the API died. A token fix, with days to live: the most maintainer thing I know.
2026: what is left
Three routes remain, and none of them is a gem that reads highlights.
The official route is the Graph API. The IG User reference I read, v25.0, lists 19 edges; one is stories, noted “Stories are only available for 24 hours.” The word “highlight” appears 0 times. That is the Facebook Login variant, with the permissions instagram_basic and pages_read_engagement; I did not check the stories edge under the newer Instagram Login. My inference: an item that only lives in a highlight is past the window, so the API reaches it only as a live story, on your own account. That is not a documented route to another account’s historical Highlights.
The scraper route is instaloader. Its issue titles are the maintenance bill: “L.get_highlights(profile) stopped working?”, “Does Instaloader actually work long-term without getting banned?”, “400 Bad Request when downloading posts”, the last still open. And –highlights still “Requires login”, according to its documentation.
The Ruby route is thin. A gem search is the start of a maintenance check, not the end. The upstream endpoint has to exist before a Ruby wrapper can call it.
So for the common job, one public highlight now and then, the answer is a web tool and no code. My criterion: what you hand over and must maintain, and how much of each promise I checked rather than read. Save only your own highlights or ones you may reuse, as Insta Saver’s page also says.
- fastdl. The file tests described here covered posts, not Highlights. In five runs nothing asked me to log in or register before the download links appeared. fastdl’s storysaver takes a public username and opens the profile on four tabs, one of them HIGHLIGHTS. The files I probed came from the POSTS tab of profiles such as NASA’s, not from highlights: a 720 x 1280 H.264 MP4 at 29.97 fps with a 57 kb/s HE-AAC stereo track, and a photo at its stored size, 1440 x 1800. Its FAQ claims no daily limits (untested) and states the boundary as a test anyone can run: “If you can’t view the post in a logged-out browser tab, FastDl.app can’t fetch it either.” Against code it wins on cost: no Instagram session, no scraper to keep alive.
- Insta Saver. I did not run it. Its FAQ says it does what fastdl’s pages do not describe: “bundle the entire highlight into a single ZIP file”, and “you get the cover image plus every single story within that highlight”. No login, “100% Free Forever”, no daily figure. If you want the whole set with its cover, Insta Saver is the page that promises it.
- IGExport. Written by its builder, per the author box, its page describes the mechanism: “a Highlight is just a saved Story bundle attached to a profile”. It states “No app to install. No signup. No Instagram login.” and “no daily cap”. Its videos come down “usually 1080p”, it says; the fastdl file I probed was 720 x 1280, so if that holds for your highlight, IGExport wins on resolution. It works item by item: “Bulk download is on the roadmap but not shipped yet.”
- Inflact. The buy option. “A free plan allows up to 2 downloads per day,” the page says (its metadata says 3), plus 8 views a day on its pricing table; past that, a paid plan and an email login, though “No Insta login is required”. What a team archiving a whole brand profile wants is paid: “the mass download feature is exclusive to a Premium plan”, with pricing to check before subscribing. That option requires a paid plan.
What I would build today
Two things, and the second is nothing.
For a brand’s own professional account: a small scheduled Ruby job against GET /{ig-user-id}/stories, with instagram_basic and pages_read_engagement, run often enough to save each story’s media inside the 24-hour window, so the archive exists before anyone picks what becomes a highlight. koala 3.7.0, released August 27, 2025, is a maintained Graph API client for Ruby; it is generic, I have not checked it for Instagram-specific helpers, and plain Net::HTTP does the job with more typing. That is where code is the right answer: your account, your token.
For someone else’s public highlight, once in a while, I would write nothing. No gem, no scraper, no session cookie in a config file. Open a web tool, paste the username, save the file you have permission to keep. Then maintain nothing.
Sources and scope
The file tests described above come from the supplied research and have not been independently repeated for this draft. Service promises are not equivalent to measured Highlights performance. Technical review is pending.
- Meta’s Basic Display retirement announcement
- Meta’s Instagram API documentation
- Koala release and package information
For Ruby implementation details, see Build a Reliable Ruby HTTP Fetcher with Net::HTTP. Record media IDs and completed file writes, finish pagination before marking a run complete, and keep tokens out of logs.
