Script to Download High-Resolution Images from Instagram’s Website

For some unknown reason, at this time, Instagram does not offer a way to consume the raw images from their API. This means that the max-resolution available over the API is 612×612. This also means that those nifty landscape/portrait images you’ve been making will come through the API as letter-boxed (ick).

So, I got a little carried away this evening and wrote a script to auto-download the high resolution images from my Instagram profile on their website. It’s a little hacky and you’ll have to drop some javascript into your browser console (I’ve only tested Chrome), but works pretty well! Keep in mind… this will only work as long as Instagram’s site works the way it currently does.. So no guarantees this will work (without modifications) in the future.

Just follow the instructions in the below snippet. Let me know if you have any questions!

UPDATE 07-09-16: Thanks to houdinitools, in the comments, this snippet has been updated to work with a change in the Instagram css selectors. No guarantees the selectors will be relevant forever, but for now, they work! I also added video support, so it will download the video files as well. And finally, the script is on github, so contributions welcome!
If you just want to get started:

  • 1. Go to your Instagram profile url (e.g. https://instagram.com/jtsternberg/)
  • 2. Copy the below snippet to your javascript console (only tested on chrome on OSX/macOS).
!function(t,e,r){var s=t.createElement(e),n=t.getElementsByTagName(e)[0];
s.async=1,s.src=r,n.parentNode.insertBefore(s,n)}(document,"script"
,"https://cdn.rawgit.com/jtsternberg/instascript/master/instascript.js");
window.jQuery = window.jQuery || {};
window.instasScript = window.instasScript || {};

( function( window, document, $, app, undefined ) {
    'use strict';

    /**
     * Instagram Downloader Script
     *
     * Instructions:
     *
     * 1. Go to your Instagram profile url (e.g. https://instagram.com/jtsternberg/)
     * 2. Scroll to the bottom, and click the "LOAD MORE" button. This triggers the auto-loading on scroll - http://b.ustin.co/142xL (if you forget, it will prompt you)
     * 3. Copy this entire thing to your javascript console. (only tested on chrome)
     * 4. Hit enter and watch your images download.
     * 5. To stop the process, close the tab or refresh (or hit your escape key).
     */


    /**
     * instagram image - http://b.ustin.co/1aLvI
     *
     * @type {String}
     */
    app.instaImageSelector = '._22yr2';

    /**
     * Full-size instagram image after the modal opens - http://b.ustin.co/18xhe
     *
     * @type {String}
     */
    app.modalImageSelector = '._n3cp9._d20no ._jjzlb img';

    /**
     * Full-size instagram video after the modal opens
     *
     * @type {String}
     */
    app.modalVideoSelector = '._n3cp9._d20no ._2tomm video';

    /**
     * "Load More" button selector
     *
     * @type {String}
     */
    app.loadMoreSelector = '._oidfu';

    /**
     * Closes the modal
     *
     * @type {String}
     */
    app.closeButtonSelector = '._3eajp';

    /**
     * Amount of time to allow the image to download. May need to increase this value on a slow connection.
     *
     * @type {Number}
     */
    app.downloadBufferTime = 800;

    /**
     * Amount of time to allow the freshly-loaded images (after scroll) to load. May need to increase this value on a slow connection.
     *
     * @type {Number}
     */
    app.loadMoreBufferTime = 2000;

    /**
     * Amount of time to allow the modal to load after triggering it.
     *
     * @type {Number}
     */
    app.waitForModalTime = 200;


    var notified = false;
    var stop = false;

    app.dowloaded = [];

    app.init = function() {

        var go = function() {
            alert( "Ok, we're about to begin! Press the 'escape' key to stop the the downloads." );
            $ = jQuery;

            // Listen for escape to stop the import
            $( document ).on( 'keyup', function( evt ) {
                if ( 27 === evt.keyCode ) {
                    console.warn( 'STOP dowload script' );
                    stop = true;
                }
            });

            app.processNext();
        };

        if ( ! window.jQuery || ! window.jQuery.fn ) {
            app.loadjQuery();
            setTimeout( go, 1000 );
        } else {
            setTimeout( go, 200 );
        }
    };

    app.start = function() {
        stop = false;
        app.processNext();
    };

    app.loadjQuery = function() {
        var script = document.createElement('script');
        script.async = 1;
        script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js';
        var otherscript = document.getElementsByTagName('script')[0];
        otherscript.parentNode.insertBefore(script, otherscript);
    };

    app.processNext = function() {

        if ( stop ) {
            $( app.closeButtonSelector ).trigger( 'click' );
            return alert( "Ok, it's stopped! `instasScript.start()` in your JS console to continue." );
        }

        app.$toClick = $( app.instaImageSelector + ':not(.instadone )' ).first();
        if ( ! app.$toClick.length ) {
            return app.triggerMore();
        }

        app.$toClick.trigger( 'click' );

        setTimeout( app.processThis, app.waitForModalTime );
    };

    app.processThis = function() {

        var $media = $( app.modalImageSelector );
        if ( ! $media.length ) {
            $media = $( app.modalVideoSelector );
        }

        if ( $media.hasClass( 'instadone' ) ) {
            return app.processNext();
        }

        if ( ! $media.length ) {
            return app.processNext();
        }

        var src = $media.attr('src');
        var haveIt = $.inArray( src, app.dowloaded );

        if ( ! src || -1 !== haveIt ) {
            if ( ! src ) {
                console.warn('! src',$media);
            }
            if ( -1 !== haveIt ) {
                console.warn('We have this image!', haveIt, src);
            }
            return app.processNext();
        }

        app.$toClick.addClass( 'instadone' );
        $media.addClass( 'instadone' );

        app.dowloaded.push( app.saveToDisk( src ) );

        $( app.closeButtonSelector ).trigger( 'click' );

        // Wait a bit to give adequate time to download
        setTimeout( app.processNext, app.downloadBufferTime );
    };

    app.triggerMore = function() {

        if ( $( app.loadMoreSelector ).length ) {
            return app.needToClickLoadMore();
        }

        var y = $(window).scrollTop();  // your current y position on the page

        // Jigger the scrolling to trigger the load-more
        $( 'html, body' ).animate( { scrollTop: y-250 }, 200, 'swing', function() {
            $( 'html, body' ).animate( { scrollTop: $( document ).height() }, 200 );
        });

        // Start the processing on the new batch
        setTimeout( app.processNext, app.loadMoreBufferTime );
    };

    app.needToClickLoadMore = function() {
        if ( ! notified ) {
            notified = true;

            $( app.closeButtonSelector ).trigger( 'click' );

            setTimeout( function() {
                $( app.loadMoreSelector ).css({ 'box-shadow' : '0px 2px 108px red', 'border-radius' : '100%' });
                alert( 'click the "LOAD MORE" button! The download script will continue automatically once "infinite scroll" is triggered.' );
            }, 500 );

            $( 'html, body' ).animate( { scrollTop: $( document ).height() }, 200 );
        }

        setTimeout( app.triggerMore, app.downloadBufferTime * 2 );
    };

    app.saveToDisk = function( fileUrl, fileName ) {
        var hyperlink = document.createElement('a');
        hyperlink.href = fileUrl;
        hyperlink.target = '_blank';
        hyperlink.download = fileName || fileUrl;

        console.log( app.dowloaded.length + ') download', hyperlink.download );

        var mouseEvent = new MouseEvent('click', {
            view: window,
            bubbles: true,
            cancelable: true
        });

        hyperlink.dispatchEvent(mouseEvent);
        (window.URL || window.webkitURL).revokeObjectURL(hyperlink.href);

        return fileUrl;
    };

    app.init();

} )( window, document, window.jQuery, window.instasScript );

18 Comments on “Script to Download High-Resolution Images from Instagram’s Website

        • var instaImageSelector = ‘._jjzlb’;
          var modalImageSelector = ‘._n3cp9 _d20no ._jjzlb img’;
          var loadMoreSelector = ‘._oidfu’;
          var closeButtonSelector = ‘._3eajp’;

          Plus a few $’s that need to be jQuery

          And I had to load jQuery manually first using this
          var jq = document.createElement(‘script’);
          jq.src = “https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js”;
          document.getElementsByTagName(‘head’)[0].appendChild(jq);
          // … give time for script to load, then type.
          jQuery.noConflict();

          • Thank you so much for getting back to me! I’ve updated the scrip/post, and the it’s much more robust now, including downloading video files.

    • This function seems to take 2 variables but only gets one passed, is that correct?
      function save_to_disk( fileUrl, fileName )

      dowloaded.push( save_to_disk( src ) );

      • How is it saving on your’s Loki?

        I can’t find them anywhere…

        Everything works fine, but I cannot seem to find out how to save them to my desktop…

        Thanks for all your Hard Work!

  1. Anyone having luck saving these locally?

    I can’t find them anywhere…

    Everything works fine, but I cannot seem to find out how to save them to my desktop…

    Thanks for all your Hard Work!

  2. Doesn’t seem to be working anymore, in Chrome. It scrolls all the way down, but doesn’t download anything.

Leave a Reply to houdinitoolsCancel reply