Before launching a campaign, you can automatically compare a list of IG accounts with the brief and produce a CSV containing only records that need attention. For each row, the script requests the profile, compares the username, privacy status, and verification status with the expected values, and saves available counts. This turns a repetitive manual check into a clear checkpoint before handing the campaign over for execution.
Goal: find discrepancies before publishing
A campaign spreadsheet typically includes an account name and a few expectations: the profile should be public, the username should match the agreed version, and the verification status should match the brief. Between preparing the list and launch, an account might change its name, become private, or turn out to be a different profile with a similar name. When rows are checked manually, it can be difficult to repeat the process and quickly identify exceptions.

For this kind of preliminary check, it is enough to retrieve a profile by username. The published jsonscraper documentation lists the GET /v1/user/by/username route with a username parameter; an optional cache_timeout is also available. The response may include a username, full name, private and verified indicators, post, follower, and following counts, as well as a biography. Read the fields from the actual response: a schema snapshot confirms their presence in the observed response, but values may vary or be absent.
Prepare the spreadsheet and validation rules
Create a CSV file named profiles.csv with the columns username, expected_private, and expected_verified. Enter the expected values true or false in the last two columns, and enter usernames without the @ symbol. If an expectation for a profile is unknown, leave the cell blank: the script should not treat a missing expectation as an error.
username,expected_private,expected_verified
examplebrand,false,true
anotheraccount,false,false
This check has two narrow aims: determine whether the returned username matches the one requested, and detect differences from the recorded privacy and verification expectations. Counts and biographies are saved for context and manual review; they are not treated as evidence of audience quality or an author’s suitability for a campaign.
Connect to the IG Scraper API
Store your access key in the JSONSCRAPER_INSTAGRAM_LICENSE_KEY environment variable. Do not put the secret in the CSV, source code, or run logs. The official IG endpoint documentation describes the route and parameter names; the API base URL is https://ig.jsonscraper.com, and the key parameter is named license_key.
Before processing the full list, make one test request for a sample row, check the JSON structure, and confirm that your account has access. Because the endpoint accepts a username, no known profile identifier or additional routes are needed for this simple scenario.
Example: requests, comparisons, and a CSV of exceptions
The following script is compatible with Python 3.8+. It reads the CSV, makes one GET request per profile, checks the external response status, and saves the original relevant fields along with the comparison result. Install the dependency with python -m pip install requests, then export the key before running the script.

import csv
import os
import time
from pathlib import Path
import requests
BASE_URL = "https://ig.jsonscraper.com/v1/user/by/username"
API_KEY = os.environ["JSONSCRAPER_INSTAGRAM_LICENSE_KEY"]
INPUT_FILE = Path("profiles.csv")
OUTPUT_FILE = Path("preflight_results.csv")
def parse_expected(value):
value = (value or "").strip().lower()
if value == "true":
return True
if value == "false":
return False
return None
def profile_from_response(payload):
# The documented observed response wraps profile fields in "ig".
if payload.get("status") != "ok":
raise ValueError("API response status is not ok")
profile = payload.get("ig")
if not isinstance(profile, dict):
raise ValueError("Response has no profile object under 'ig'")
return profile
with INPUT_FILE.open(newline="", encoding="utf-8") as source:
rows = list(csv.DictReader(source))
results = []
for row in rows:
requested = (row.get("username") or "").strip().lstrip("@")
if not requested:
results.append({
"requested_username": "",
"result": "missing_username",
"error": "username is empty",
})
continue
try:
response = requests.get(
BASE_URL,
params={"username": requested, "license_key": API_KEY},
timeout=30,
)
response.raise_for_status()
profile = profile_from_response(response.json())
actual_username = profile.get("username")
actual_private = profile.get("is_private")
actual_verified = profile.get("is_verified")
expected_private = parse_expected(row.get("expected_private"))
expected_verified = parse_expected(row.get("expected_verified"))
checks = []
if actual_username and actual_username.casefold() != requested.casefold():
checks.append("username_mismatch")
if expected_private is not None and actual_private != expected_private:
checks.append("privacy_mismatch")
if expected_verified is not None and actual_verified != expected_verified:
checks.append("verification_mismatch")
results.append({
"requested_username": requested,
"username": actual_username,
"full_name": profile.get("full_name"),
"is_private": actual_private,
"is_verified": actual_verified,
"media_count": profile.get("media_count"),
"follower_count": profile.get("follower_count"),
"following_count": profile.get("following_count"),
"result": "review" if checks else "matched",
"checks": ";".join(checks),
"error": "",
})
except (requests.RequestException, ValueError, KeyError) as exc:
results.append({
"requested_username": requested,
"result": "request_or_response_error",
"error": str(exc),
})
# A small delay spaces requests; it is not a documented quota guarantee.
time.sleep(0.5)
fieldnames = sorted({key for item in results for key in item})
with OUTPUT_FILE.open("w", newline="", encoding="utf-8") as destination:
writer = csv.DictWriter(destination, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(results)
print("Saved", len(results), "rows to", OUTPUT_FILE)
The code checks the observed response wrapper specifically: the outer status and the ig profile object. If the provider changes the format, the structure check stops processing that record and saves an error rather than silently marking it as a match. The script does not print the key or put it in the output file.
How to read the results
In preflight_results.csv, rows with the matched status passed the specified comparisons. A review result means one or more parameters differ from the brief; the checks column shows which ones. A request or response error is marked separately, so unavailable data does not appear to be a confirmed match.
Follower and post counts help a person see a current profile snapshot alongside the submission. These are point-in-time values from the response to the request. To assess changes over time, save separate dated runs; a single check contains no history. Fields may be empty, in which case the record can still be used to check identity and other available indicators, but not to compare a missing count.
Automate the process before campaign launch
After manually checking a test CSV, add the script to a schedule or campaign-preparation step. For reproducible checks, keep the original list separately, record the run date, and save the results CSV in a restricted work repository. If usernames may change, use a stable row identifier from your system for reprocessing.
As the list grows, add a concurrency limit, retries only for temporary network errors, and a separate log of error codes without secrets. Do not retry indefinitely for an invalid key or malformed username. Add cache_timeout only in accordance with your freshness policy: the documentation states that caching is disabled for IG by default, and a value greater than zero enables caching for the specified period.
Profile checks reduce manual comparison to a specific list of exceptions: username, privacy, verification, and available counts appear in one table before the campaign starts. For API parameters and current integration options, consult the IG Scraper API page and the route documentation.