Instagram Checkpoint Challenge Required

a quick and dirty solution

Posted by silau on October 15, 2019

I have tried a few python libraries for getting Instagram data and I found this one is the best:

Instagram Private API

Thanks to Ping's great work, we could access many functions that are only available through the official app, such as:

  • Multiple feeds, such as user feed, location feed, tag feed, popular feed
  • Post a photo or video to your feed or stories
  • Like/unlike posts
  • Get post comments
  • Post/delete comments
  • Like/unlike comments
  • Follow/unfollow users
  • User stories
  • And more!

For new users, you might experience Checkpoint Challenge Required issue during app login.

Long ago, you could solve the challenge in a web browser on the same machine and it will fix the issue.

Sadly you can't do this any more, you need to solve this checkpoint challenge in the first place.

I tried to mimic the solution from Instagram Scraper as suggested by others, so here comes to the solution (quick and dirty):

  1. Override login method (in endpoints/accounts)
  2. Expose part of the _call_api method (in client)
  3. Capture the checkpoint challenge exception
  4. Handle the exception by mimic Instagram Scraper's login_challenge method

As Instagram keeps changing its API use case, this solution may become obsolete soon.

So use the quick fix below with caution.

import hashlib
import string
import random
import time
import re
import requests
import json
import gzip

from io import BytesIO
from instagram_private_api import Client, ClientCompatPatch
from instagram_private_api.client import compat_urllib_parse, compat_urllib_request, compat_urllib_error, ErrorHandler

from instagram_web_api import Client as WebClient

class MyAppClient(Client):
    
    def login(self):
        """Login."""

        print('overrided login()')

        prelogin_params = self._call_api(
            'si/fetch_headers/',
            params='',
            query={'challenge_type': 'signup', 'guid': self.generate_uuid(True)},
            return_response=True)

        login_params = {
            'device_id': self.device_id,
            'guid': self.uuid,
            'adid': self.ad_id,
            'phone_id': self.phone_id,
            '_csrftoken': self.csrftoken,
            'username': self.username,
            'password': self.password,
            'login_attempt_count': '0',
        }

        try:
            """
            login_response = self._call_api(
            'accounts/login/', params=login_params, return_response=True)
            """

            url = 'https://i.instagram.com/api/v1/accounts/login/'
            params = login_params

            headers = self.default_headers
            headers['Content-type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
            
            json_params = json.dumps(params, separators=(',', ':'))
            hash_sig = self._generate_signature(json_params)
            post_params = {
                'ig_sig_key_version': self.key_version,
                'signed_body': hash_sig + '.' + json_params
            }

            data = compat_urllib_parse.urlencode(post_params).encode('ascii')
            req = compat_urllib_request.Request(url, data, headers=headers)

            try:
                response = self.opener.open(req, timeout=self.timeout)
            except compat_urllib_error.HTTPError as e:
                response_text = json.loads(e.read().decode('utf8'))
                checkpoint_url = response_text.get('challenge').get('url')
                self.login_challenge(checkpoint_url, headers)
                
        except Exception as e:
            print('unhandled exception', e)

    def login_challenge(self, checkpoint_url, headers):

        try:
            print('redirecting to ..', checkpoint_url)
            headers['X-CSRFToken'] = self.csrftoken
            headers['Referer'] = checkpoint_url
            
            mode = int(input('Choose a challenge mode (0 - SMS, 1 - Email): '))
            challenge_data = {'choice': mode}
            data = compat_urllib_parse.urlencode(challenge_data).encode('ascii')
            
            req = compat_urllib_request.Request(checkpoint_url, data, headers=headers)
            response = self.opener.open(req, timeout=self.timeout)

            code = input('Enter code received: ')
            code_data = {'security_code': code}
            data = compat_urllib_parse.urlencode(code_data).encode('ascii')

            req = compat_urllib_request.Request(checkpoint_url, data, headers=headers)
            response = self.opener.open(req, timeout=self.timeout)

            if response.info().get('Content-Encoding') == 'gzip':
                buf = BytesIO(response.read())
                res = gzip.GzipFile(fileobj=buf).read().decode('utf8')
            else:
                res = response.read().decode('utf8')
    
        except compat_urllib_error.HTTPError as e:
            print('unhandled exception', e)