Before a campaign launch, you can process a list of IG accounts with a script and get a JSON report containing the API response for each username. The jsonscraper IG Scraper API endpoint returns an external status and a profile object; the observed schema includes the username, privacy and verification indicators, and counts for posts, followers, and following. These fields help identify records for manual review, but do not by themselves explain why a response is missing or unexpected.

The problem: The account list looks correct, but is it ready to use?
A campaign spreadsheet may include renamed accounts, typos, and private profiles. If the team starts analyzing the list without a preliminary check, someone has to open the accounts one by one. An automated pass reduces manual work and creates a consistent log of exactly what the API returned for each requested username.
The goal of this workflow is limited: process the list, save the actual HTTP responses and JSON, and flag profiles with campaign-relevant indicators for manual review. The report records observed data; it does not determine why a profile was not returned or why a request failed.
What the request checks
The jsonscraper documentation specifies the GET \/v1\/user\/by\/username endpoint. The required parameter is username; the key is passed as license_key. The optional cache_timeout parameter enables caching for a specified number of seconds, while 0 leaves it disabled. The observed successful-response schema contains an outer status and an ig object with profile fields.
For diagnostics, distinguish three facts: whether the HTTP request succeeded; whether the parsed JSON contains an ig object; and which fields are present in that object. If any step does not complete as expected, the script can record a technical result and the original response. That result indicates that a check is needed, but does not establish the cause of the failure.
Prepare the input data and key
Create a usernames.txt file with one username per line, without the @ symbol. Remove blank lines and duplicates, keeping only accounts relevant to the campaign. For later comparison, store the check date and project identifier separately.
Store the key in the JSONSCRAPER_INSTAGRAM_LICENSE_KEY environment variable, not in source code or a repository:
export JSONSCRAPER_INSTAGRAM_LICENSE_KEY="your_key"
python3 check_profiles.py
The example uses the Python 3.8+ standard library and does not require installing HTTP packages.
Example: Request profiles and write a report
The script processes the list one username at a time. For a successful JSON response, it saves the actual body and available profile fields; for an HTTP or network error, it records the technical outcome. Missing fields remain null, and the raw response body is saved if it could be read.
import json
import os
import time
from datetime import datetime, timezone
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
API_KEY = os.environ.get("JSONSCRAPER_INSTAGRAM_LICENSE_KEY")
if not API_KEY:
raise SystemExit("Set JSONSCRAPER_INSTAGRAM_LICENSE_KEY")
BASE_URL = "https:\/\/ig.jsonscraper.com\/v1\/user\/by\/username"
with open("usernames.txt", encoding="utf-8") as f:
usernames = list(dict.fromkeys(
line.strip().lstrip("@") for line in f if line.strip()
))
results = []
for username in usernames:
params = urlencode({"username": username, "license_key": API_KEY})
request = Request(f"{BASE_URL}?{params}", method="GET")
checked_at = datetime.now(timezone.utc).isoformat()
try:
with urlopen(request, timeout=30) as response:
http_status = response.status
raw_body = response.read().decode("utf-8")
try:
payload = json.loads(raw_body)
json_error = None
except json.JSONDecodeError as exc:
payload = None
json_error = str(exc)
profile = payload.get("ig") if isinstance(payload, dict) else None
record = {
"requested_username": username,
"checked_at": checked_at,
"http_status": http_status,
"api_status": payload.get("status") if isinstance(payload, dict) else None,
"check_result": "profile_returned" if isinstance(profile, dict) else "unexpected_or_missing_profile_object",
"response": payload if payload is not None else raw_body,
}
if json_error:
record["json_error"] = json_error
if isinstance(profile, dict):
record["returned_username"] = profile.get("username")
record["is_private"] = profile.get("is_private")
record["is_verified"] = profile.get("is_verified")
record["media_count"] = profile.get("media_count")
record["follower_count"] = profile.get("follower_count")
record["following_count"] = profile.get("following_count")
results.append(record)
except HTTPError as exc:
body = exc.read().decode("utf-8", errors="replace")
results.append({
"requested_username": username,
"checked_at": checked_at,
"check_result": "http_error",
"http_status": exc.code,
"response": body,
})
except (URLError, TimeoutError) as exc:
results.append({
"requested_username": username,
"checked_at": checked_at,
"check_result": "request_error",
"detail": str(exc),
})
time.sleep(0.5)
with open("profile-check.json", "w", encoding="utf-8") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f"Results saved: {len(results)}")
This is an integration example, not a report of a test that was performed. The key is passed in the license_key parameter but is not printed. The full response may contain information that should be access-controlled according to your team’s data-retention rules.
How to read the results
A profile_returned record means the script received a JSON ig object. Compare requested_username with returned_username and review the indicators relevant to the campaign workflow. For example, if the campaign requires a public profile, is_private: true can be flagged for manual review.

The http_error, request_error, and unexpected_or_missing_profile_object results indicate only the step at which the script failed to receive the expected structure. They do not prove that an account was deleted, made private, or became unavailable for a specific reason. Save the response, check the username and key, then retry the request or contact the service’s regular support team.
If a field is missing, leave it unknown—do not interpret its absence as zero or false. Profile counts describe the state returned at the time of the request. The timestamp helps distinguish this snapshot from the results of a later run.
Automate without losing observability
Move the run into a task scheduler or an existing ETL workflow. Store the check date, requested username, result, status, and response body. As a separate step, you can load the JSON into a table and send only records that need review to a specialist.
To detect changes, compare snapshots of the same profile using selected fields. A change in the number of posts is a reason to open the profile and check it, not an exact date for when a post appeared. The follower count is also a value from the time of the request, so a history of observations is built from saved snapshots.
For a large list, set a controlled rate, add bounded retries, and keep an error log. Do not include the key in URL logs. Storing the input list and results separately helps identify which accounts have already been processed.
Expected result
The output is a JSON file containing a processing result for each submitted username, a timestamp, available attributes, and the saved response. Before passing the list to a campaign, you can filter matching usernames, private profiles, and technical cases for manual review. The team sets the criteria for the next step.
The endpoint and parameters are described in the IG API documentation; product information is available on the IG Scraper API page. Start with a small sample, check the actual response format, and configure the report rules for your workflow.