Instagram prevents right-clicking on photos and dragging them to your desktop. This script strips those CSS restrictions — and keeps stripping them as you scroll and new posts load — no extensions or third-party sites required.
Why Can’t You Right-Click Instagram Photos?
If you try to right-click a photo on Instagram you’ll notice the context menu either doesn’t appear at all, or the “Save image as…” option is missing. Open DevTools and inspect any image — you’ll see something like this layered on top of it:
pointer-events: none;
user-select: none;
z-index: 1;
Instagram doesn’t hide the image or encrypt it. The full-resolution photo is already sitting in your browser’s memory — the browser already downloaded it to display it. Instagram just places invisible overlay elements on top of images and then sets pointer-events: none on the <img> elements themselves so that your mouse clicks land on the overlay (which does nothing) instead of on the image.
This script reverses those CSS overrides directly in the page — and crucially, keeps reversing them as you scroll and new posts are injected into the DOM.
Why Persistence Matters
A naive one-shot approach — run the script once, unlock everything on the page — has an obvious weak point: Instagram’s feed is infinite-scroll. As you scroll down, Instagram’s JavaScript continuously:
- Fetches new batches of posts from the server
- Creates brand-new
<img>DOM nodes and inserts them into the page - Those new nodes have Instagram’s default CSS shields applied from the start
A one-time querySelectorAll only sees elements that exist at the moment it runs. Every image that loads after that call is invisible to it — still locked.
The updated script solves this with a MutationObserver. Instead of a snapshot, it registers a persistent listener that the browser calls every time new DOM nodes are added to the page — whether by scrolling, clicking “Load more”, or anything else Instagram’s JavaScript does. Each time the observer fires, it re-runs the unlock pass over every image on the page.
The result: you run the script once and then scroll freely. Every photo that loads — now or five minutes from now — is unlocked automatically.
Using it on Desktop
Step 1 — Open Instagram
Go to instagram.com and navigate to the photo or profile page you want.
Step 2 — Open the Browser Console
Windows / Linux: Press F12 or Ctrl + Shift + I, then click the Console tab.
Direct shortcut: Ctrl + Shift + J (Chrome) jumps straight to the Console.
Mac: Press Cmd + Option + I, then click the Console tab.
Direct shortcut: Cmd + Option + J (Chrome) jumps straight to the Console.
Step 3 — Paste and Run the Script
Paste the following code into the console and press Enter:
javascript:(function() {
console.log("%c 🛡️ Shield-Killer Observer Active...", "color: #ff00ff; font-weight: bold;");
const killShields = () => {
document.querySelectorAll('img').forEach(img => {
img.style.setProperty('z-index', '999', 'important');
img.style.setProperty('pointer-events', 'auto', 'important');
img.style.setProperty('position', 'relative', 'important');
img.style.setProperty('user-select', 'auto', 'important');
});
};
// Run once immediately
killShields();
// Set up the MutationObserver to watch for new posts
const observer = new MutationObserver((mutations) => {
killShields();
});
// Start watching the entire body for added elements
observer.observe(document.body, { childList: true, subtree: true });
alert("Persistent Sniper Active! Shields will be auto-killed as you scroll.");
})();
You’ll see a bright pink “🛡️ Shield-Killer Observer Active…“ message in the console, followed by a confirmation alert. Every image on the page is now right-clickable — and any new images that load as you scroll will be unlocked automatically.
Step 4 — Save the Photo
Right-click any photo and choose Save image as… — or drag it straight to your desktop or a folder.
<img> you can interact with in the same way. Stick to Feed and Profile pages for reliable saving.
Using it on Mobile (Bookmarklet)
Mobile browsers don’t have a DevTools console, but they support bookmarklets — bookmarks whose URL is a JavaScript snippet that runs on the current page when you tap it.
Step 1 — Create a New Bookmark
In your mobile browser, bookmark any page. The URL doesn’t matter — you’ll replace it in the next step.
Step 2 — Edit the Bookmark
Open your bookmarks, find the one you just saved, and tap Edit:
- Change the name to something like
IG Image Unblock - Delete the entire URL and paste this one-liner in its place (copy the whole thing — it must be one continuous line):
javascript:(function(){console.log("%c \uD83D\uDEE1\uFE0F Shield-Killer Observer Active...","color: #ff00ff; font-weight: bold;");const killShields=()=>{document.querySelectorAll('img').forEach(img=>{img.style.setProperty('z-index','999','important');img.style.setProperty('pointer-events','auto','important');img.style.setProperty('position','relative','important');img.style.setProperty('user-select','auto','important');});};killShields();const observer=new MutationObserver(()=>{killShields();});observer.observe(document.body,{childList:true,subtree:true});alert("Persistent Sniper Active! Shields will be auto-killed as you scroll.");})();
Save the bookmark.
Step 3 — Run It on Instagram
- Open Instagram in your mobile browser and navigate to the feed or profile you want.
- Tap the address bar, type the name you gave the bookmark (e.g.
IG Image Unblock), and when it appears in the dropdown, tap it. - Dismiss the confirmation alert, then scroll freely — long-press any photo to save it.
How the Code Works
Here’s a plain-English breakdown for the curious.
The IIFE Wrapper
(function() {
// ...
})();
This is an Immediately Invoked Function Expression (IIFE). Wrapping the code in a function and calling it immediately keeps all variables — including killShields and observer — scoped locally, so the script doesn’t pollute the page’s global namespace or accidentally clash with Instagram’s own JavaScript variables.
Styled Console Logging
console.log("%c 🛡️ Shield-Killer Observer Active...", "color: #ff00ff; font-weight: bold;");
console.log accepts CSS formatting when the message starts with %c. The second argument is a CSS string applied to everything after %c. This is a small UX touch — the bright magenta text makes it immediately obvious in a crowded console that the observer is running and ready.
The killShields Helper Function
const killShields = () => {
document.querySelectorAll('img').forEach(img => {
img.style.setProperty('z-index', '999', 'important');
img.style.setProperty('pointer-events', 'auto', 'important');
img.style.setProperty('position', 'relative', 'important');
img.style.setProperty('user-select', 'auto', 'important');
});
};
This extracts the unlock logic into a named function so it can be called from two places: once immediately on startup, and once each time the observer fires. Without this, the same code would need to be duplicated.
querySelectorAll('img') returns every <img> element currently in the DOM. The loop applies four inline style overrides to each one using setProperty with 'important' — the programmatic equivalent of !important in a stylesheet — so Instagram’s own CSS rules can’t win the specificity battle:
pointer-events: auto— re-enables mouse clicks and right-clicks (Instagram setspointer-events: noneto pass clicks through to an invisible overlay div instead)z-index: 999— lifts the image above overlay divs in the stacking order (999 is pragmatically high;2147483647is the maximum if you ever need more)position: relative— required forz-indexto take effect;z-indexis ignored on statically positioned elementsuser-select: auto— re-enables drag-and-select, which Instagram disables on profile grids
Running Immediately
killShields();
This first call handles every image that was already in the DOM when the script ran. Without it, all currently visible photos would remain locked until the observer first fires.
The MutationObserver — Watching for New Posts
const observer = new MutationObserver((mutations) => {
killShields();
});
observer.observe(document.body, { childList: true, subtree: true });
MutationObserver is a browser API that lets you watch for changes to the DOM and run a callback whenever they occur. It’s far more efficient than a polling loop (setInterval) because the browser only calls the callback when something actually changes, rather than on a fixed timer.
The two options passed to observer.observe are:
childList: true— watch for direct children being added or removed from the targetsubtree: true— extend that watch to all descendants of the target, not just immediate children
Together they tell the observer: “whenever any element anywhere inside document.body is added or removed, call killShields().” Instagram’s infinite-scroll loader inserts entire post subtrees deep inside the DOM — subtree: true is what catches those insertions regardless of how deeply nested they are.
The Confirmation Alert
alert("Persistent Sniper Active! Shields will be auto-killed as you scroll.");
A simple alert() to confirm the observer is running before you close the console and start scrolling. Dismiss it and the observer keeps running silently in the background.
Why Does Instagram Block This?
Platforms restrict right-clicking and image saving for a few reasons:
- Copyright protection — Many photos are the intellectual property of the creator or a brand, and the platform wants to discourage easy copying.
- Engagement funnel — Keeping content inside the platform (via “Share” or “Save to Collection”) keeps users on-site and feeds their recommendation algorithms.
- DRM theatre — In practice these restrictions are CSS-only and trivially bypassed (as this post demonstrates), so they function more as a mild friction than a real technical barrier.
None of these measures prevent the browser from downloading the image — they only restrict what you can do with it once it’s rendered on screen. The image data is already on your machine the moment it appears in your browser.
Disclaimer: This script is provided for educational purposes only. It demonstrates standard browser APIs (
MutationObserver,pointer-events,z-index,user-select) that are freely documented and publicly available. Downloading content from Instagram may be against Instagram’s Terms of Service. Only save photos you own, have explicit permission to download, or that are explicitly made available for download. Respect copyright and the work of content creators.