Embed the widget
Paste this where you want the widget to appear. It opens as a tool: your visitors paste any public link.
<iframe
src="https://insta.flashdl.one/embed/?theme=light"
title="Downloader for Instagram"
width="100%" height="640"
style="border:0;width:100%;max-width:560px;color-scheme:light"
loading="lazy"
referrerpolicy="strict-origin-when-cross-origin"
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-downloads"
allow="clipboard-read; clipboard-write">
</iframe>| Attribute | Why it is there |
|---|---|
title |
Names the frame for screen readers. |
width, style |
Full width of its column, up to 560px. The widget fits anything from 320px up. color-scheme:light stops a page with a dark color scheme from painting an opaque box behind the frame. |
height |
640px suits most pages. Add the auto-height script to size it to its content instead. |
loading="lazy" |
The widget loads only when a visitor scrolls near it. |
referrerpolicy |
Tells the widget your site’s name and nothing more. Your page paths stay private. |
sandbox |
Limits what the widget can do. See Sandbox. |
allow |
Lets the Paste button read the clipboard, and Copy write to it. Without it, visitors can still paste with the keyboard or a long press. |
Sandbox
We recommend the sandbox attribute. It lists exactly what the widget may do. Anything not listed, the browser blocks.
| Token | What it allows | Without it |
|---|---|---|
allow-scripts |
The widget to run. | Nothing works. |
allow-same-origin |
The widget to reach its own server and remember the sponsor limit. | Results can’t load. |
allow-popups |
The first Download to open the sponsor tab, and links such as Open on Instagram to open. | No new tabs. Downloads still work, but this tab is what keeps FlashDL free. Our terms ask you to keep this token. |
allow-popups-to-escape-sandbox |
New tabs to open as normal pages. | New tabs inherit the sandbox and may not display correctly. |
allow-downloads |
Download to save files. | Chrome and Edge block downloads without telling anyone. |
Never add allow-top-navigation or allow-top-navigation-by-user-activation. The widget doesn’t need them, and leaving them out means the browser itself prevents the widget from navigating your page.
Parameters
Add parameters to the src address after /embed/.
| Parameter | Values | Default | What it does |
|---|---|---|---|
url |
A link or @username, URL-encoded |
none | Optional. Without it, the widget opens as a tool. With it, the widget opens with that post, Reel, profile, Story or Highlight already loaded. Visitors can still paste another link. |
theme |
light, dark, auto |
light |
light unless set; auto follows each visitor’s light or dark setting from the first frame. Any other value is treated as light. |
Accepted links: posts (/p/), Reels (/reel/, /reels/), /tv/, profiles, @username or a bare username, Stories (/stories/username/…) and Highlights (/stories/highlights/…). Links from m.instagram.com, without www, or with share parameters such as igsh all work. Short instagr.am links and /share/ links are not supported: open them in Instagram, tap Share, then Copy link, and use that.
URL-encoding the link
Encode the value of url so its own ?, & and # don’t break the address.
https://insta.flashdl.one/embed/?url=https%3A%2F%2Fwww.instagram.com%2Freel%2FABC123%2F&theme=dark
https://insta.flashdl.one/embed/?url=%40nasa&theme=autoIn code:
const src = 'https://insta.flashdl.one/embed/?url=' + encodeURIComponent(link) + '&theme=auto';<?php $src = 'https://insta.flashdl.one/embed/?url=' . rawurlencode($link) . '&theme=auto'; ?>In HTML attributes, write & as & if your editor or validator asks for it. Both work in browsers.
One widget or many
- Most sites need one. A single open tool handles every kind of public link.
- Showing several posts? Give each its own iframe with its own
url. Each widget looks up its link only when it scrolls into view, so a long page doesn’t fire every lookup at once. - Building pages with code? Make the
urlvalue from your post’s link, as in the examples above.
Auto-height
The widget reports its height to your page whenever its content changes. Add this script once, anywhere below the iframes, and every FlashDL widget on the page sizes itself. The message format, flashdl:height, is the same as the FlashDL widget for YouTube.
<script>
window.addEventListener('message', function (e) {
if (e.origin !== 'https://insta.flashdl.one' || !e.data || e.data.type !== 'flashdl:height') return;
var h = parseInt(e.data.height, 10);
if (!h || h < 200) return;
var frames = document.getElementsByTagName('iframe');
for (var i = 0; i < frames.length; i++) {
if (frames[i].contentWindow === e.source) frames[i].style.height = h + 'px';
}
});
</script>The origin check makes sure only our widget can resize your frames. Keep the height attribute on the iframe as the starting size.
Using the YouTube widget too? One script covers both. Replace the first line inside the function with:
if ((e.origin !== 'https://insta.flashdl.one' && e.origin !== 'https://embedded.flashdl.one') || !e.data || e.data.type !== 'flashdl:height') return;Page link
Optional. Visitors sometimes arrive from inside an app such as Instagram or TikTok, whose built-in browsers often block downloads. The widget then offers a Copy link button so they can finish in their phone’s browser. Without the handshake below, that button copies a link to the widget on insta.flashdl.one with their Instagram link filled in. To send them back to your exact page instead, add this handshake:
<script>
window.addEventListener('message', function (e) {
if (e.origin !== 'https://insta.flashdl.one' || !e.data || e.data.type !== 'flashdl:ready') return;
e.source.postMessage({ type: 'flashdl:host', url: location.href }, 'https://insta.flashdl.one');
});
</script>The widget keeps this address in the visitor’s browser, for that button only. Only your site’s name, which the widget already knows, is used for the sponsor link and analytics.
Messages and events
The widget and your page talk through postMessage. Every message is an object with a type. All of them are optional to handle.
From the widget to your page
type |
Fields | When |
|---|---|---|
flashdl:ready |
v (protocol version, currently 1) |
Once, when the widget is ready to use. |
flashdl:height |
height (CSS pixels) |
Whenever the content height changes. |
flashdl:event |
name, kind, code |
When something happens that you may want to count. |
flashdl:scrollIntoView |
top (CSS pixels from the top of the widget) |
When a result or error appears out of view. Optional to handle. |
Events sent with flashdl:event:
name |
Fields | When |
|---|---|---|
search |
kind |
A lookup started. |
result |
kind |
A result is showing. |
download_start |
kind |
A visitor started a download. |
sponsor_open |
none | A Download tap asked the browser for the sponsor tab. A pop-up blocker can still stop it. |
error |
kind, code |
A lookup failed. code is a short reason, such as not_found or timeout. |
cancel |
none | The visitor cancelled a lookup. |
kind says what the event is about, such as media (a post, Reel or carousel), profile, story or highlight. Treat values you don’t know as “other”. Events never include the link, username or caption.
From your page to the widget
type |
Fields | What it does |
|---|---|---|
flashdl:host |
url |
Sets the page link. See Page link. |
flashdl:setTheme |
theme: auto, light or dark |
Switches the theme without reloading. Useful if your site has its own light and dark switch. |
flashdl:setUrl |
url: a link or @username |
Looks it up, as if a visitor had pasted it. |
Send them to the widget’s origin only:
frame.contentWindow.postMessage({ type: 'flashdl:setTheme', theme: 'dark' }, 'https://insta.flashdl.one');Listen for events the same way as auto-height:
window.addEventListener('message', function (e) {
if (e.origin !== 'https://insta.flashdl.one' || !e.data || e.data.type !== 'flashdl:event') return;
console.log(e.data.name, e.data.kind, e.data.code);
});Content-Security-Policy
If your site sends a Content-Security-Policy header, allow the widget’s frame:
frame-src https://insta.flashdl.one;- If your policy has no
frame-src, add it, or add the origin tochild-srcordefault-src, whichever your policy uses. - The widget’s images and videos load inside its own frame, under our policy, so you don’t need to allow Instagram servers.
- If you inline the auto-height script, your
script-srcmust allow it with a hash or nonce, or move the script into a file on your own domain. - A
Permissions-Policyheader that blocksclipboard-readorclipboard-writeoverrides theallowattribute. Visitors can still paste by hand. - Pages that send
Cross-Origin-Embedder-Policy: require-corpcan’t show the widget.
Troubleshooting
| What you see | Likely cause | Fix |
|---|---|---|
| Tapping Download does nothing | The sandbox attribute is missing allow-downloads. Chrome and Edge then block downloads silently. |
Add allow-downloads, or remove the sandbox attribute. |
| The widget never shows results | The sandbox attribute is missing allow-same-origin or allow-scripts. |
Use the full token list from Embed the widget. |
| An empty box where the widget should be | Your Content-Security-Policy doesn’t allow the frame, or a browser extension blocks it. |
Add frame-src https://insta.flashdl.one. |
| The widget is cut off, or scrolls inside | The fixed height is too small for the result. | Add the auto-height script, or raise height. |
| The theme doesn’t match your site | The widget is light unless theme says otherwise, and auto follows the visitor’s device, not your site’s own light and dark switch. |
Set theme to match, or send flashdl:setTheme when your switch changes. |
| On iPhone, a download seems to vanish | Safari saves to Files › Downloads, not Photos. | Open the file in Files, tap Share, then Save Video or Save Image. The download list is also in Safari’s address bar. |
| Downloads fail inside Instagram, Facebook or TikTok | Their in-app browsers often block downloads. | Visitors open the page in their phone’s browser. The widget shows them how. Add the page link handshake so they land on the right page. |
| A profile won’t load | The account is private, renamed or deleted, or our source couldn’t reach it this time. | Try again, or paste a link to one of the account’s posts. |
| A download fails after the result has been open for hours | Instagram file links expire, after about a day for videos. | Paste the link again for fresh links. |
Limits
- Public content only. Private accounts are not supported, and the widget never asks anyone to log in.
- Video up to 720p. That is the highest quality the source provides for Reels, posts, Stories and Highlights. Photos come at the size Instagram provides, often 1080px wide.
- Stories are live for 24 hours. A link to one Story shows all of that account’s current Stories, with the linked one first. If it has expired, the widget shows the ones still live.
- No separate Reels tab on profiles. Reels appear with the other videos in the Posts grid.
- File names are the ones Instagram servers give, which can be long.
- Links in a result expire. Instagram file links last about a day for videos and a few days for photos. A fresh lookup fixes it.
- Large files download straight from Instagram servers to your visitor’s device, so speed depends on their connection. In-app browsers may interrupt long downloads.
- Now and then a public account can’t be loaded from our source. A direct link to one of its posts usually still works.
Changelog
| Date | Version | Change |
|---|---|---|
| 4 October 2026 | 1.0 | First release: open tool, url and theme parameters, auto-height, page link handshake and events. |