Skip to main content

How to Export Indigo Proxy Details with Python

You can easily generate JSON proxy credentials lists from any set of Indigo X browser profiles via Python using their profile IDs! This article will guide you through the process of creating these lists efficiently.

Before You Start

Ensure you have a Python environment set up with the following packages installed:

  • os
  • json
  • dotenv
  • hashlib
  • requests

Save the script proxies_to_json.py in your desired folder.

info

Configuration values such as credentials, Folder ID, and file paths are managed within the script or an accompanying .env file. You'll need to set these according to your setup.

The Python Script: proxies_to_json.py

import os
import json
import dotenv
import hashlib
import requests

dotenv.load_dotenv()

# Credentials are pulled from a local .env file
USERNAME = os.getenv("indigoUSERNAME")
PASSWORD = os.getenv("indigoPASSWORD")

# Insert Your FolderID here (optional, used if you customize profile_search)
FOLDERID = "91f042e6-xxx-4e1f-adee-5eed6bb47d60"

# Insert your profile_ids.json filepath here (used for option 3)
LIST_PATH = "C:/.../files/pid_list.json" # Example: "C:/Users/YourUser/indigo_profiles/profile_ids.json"

# Paste your string values manually (used for option 1)
LIST_MANUAL = [
"95f6d02c-xxxx-47c4-b1d4-369801f2a37c",
"48da90d8-xxxx-40a2-8ccb-2d9e7e3eaebb",
"e2f9d96a-xxxx-4439-ae74-10beda6bf109",
"fffca377-xxxx-495e-a408-3a98716e14ea",
"f3559ca3-xxxx-479c-8a8a-c4b831e8f78b",
"1c1e09dc-xxxx-4495-979b-7cb805a3a8a1",
"a66ba910-xxxx-48ac-a6d1-615f996b3a1d",
"f17140f4-xxxx-47c5-96d5-1b9fd184203b",
"0a505d93-xxxx-4ba9-bd25-d37bf8bb168d",
]

# API-Related Objects
LOCALHOST = "http://127.0.0.1"
indigo_BASE = "https://api.indigo.com" # Main API endpoint
LAUNCHERV1 = "https://launcher.indigobrowser.com:45011/api/v1" # Launcher API endpoint
HEADERS = {"Accept": "application/json", "Content-Type": "application/json"}

# Login Function
def signin() -> str:
payload = {
"email": USERNAME,
"password": hashlib.md5(PASSWORD.encode()).hexdigest(),
}

r = requests.post(f"{indigo_BASE}/user/signin", json=payload)

if r.status_code != 200:
print(f"\nError during login: {r.status_code} - {r.text}\n")
return ""
else:
try:
response_data = r.json().get("data", {})
token = response_data.get("token")
if token:
print("Successfully signed in.")
return token
else:
print(f"\nError during login: Token not found in response. {r.json()}\n")
return ""
except requests.exceptions.JSONDecodeError:
print(f"\nError during login: Could not decode JSON response. {r.text}\n")
return ""

# Search Profiles (example: recently created by the Bulk Create function, called "TempName")
def profile_search():
url = f"{indigo_BASE}/profile/search"
body = {
"is_removed": False, # Search for active profiles? True/False
"limit": 100, # How many profile results to get
"offset": 0, # Check Indigo Documenter page for full parameter breakdown
"search_text": "", # e.g., "TempName" or "" for all
"storage_type": "all", # "local", "cloud", "all"
"order_by": "created_at", # "name", "created_at", "updated_at"
"sort": "asc", # "asc" or "desc"
}
print(f"Searching profiles with parameters: {body}")
response = requests.request("POST", url, headers=HEADERS, json=body)

if response.status_code != 200:
print(f"Error during profile search: {response.status_code} - {response.text}")
return {"data": {"total_count": 0, "profiles": []}} # Return empty structure on error

try:
resp_json = response.json()
return resp_json
except requests.exceptions.JSONDecodeError:
print(f"Error decoding JSON from profile search: {response.text}")
return {"data": {"total_count": 0, "profiles": []}} # Return empty structure on error

# Obtain a list of ProfileIDs retrieved by the Profile Search endpoint
def get_profile_ids():
profile_list_response = profile_search()

if not profile_list_response or profile_list_response.get("data", {}).get("total_count") == 0:
print("No profiles found or error in response during profile search.")
return []

profiles_data = profile_list_response.get("data", {}).get("profiles", [])
if profiles_data:
profile_ids = [profile["id"] for profile in profiles_data if "id" in profile]
print(f"Found {len(profile_ids)} profile IDs from search.")
return profile_ids
else:
print("Error: 'profiles' key not found or empty in profile search response.")
return []

# Use Profile Metas endpoint to get the Proxy information registered.
def search_proxy_metas(option_call):
url = f"{indigo_BASE}/profile/metas"
profile_ids_to_query = []

if option_call == "1": # Manual List
profile_ids_to_query = LIST_MANUAL
print(f"Using manual list of {len(profile_ids_to_query)} profile IDs.")
elif option_call == "2": # Profile Search
profile_ids_to_query = get_profile_ids()
if not profile_ids_to_query:
print("No profile IDs obtained from profile search. Aborting proxy meta search.")
return
print(f"Using {len(profile_ids_to_query)} profile IDs from profile search.")
elif option_call == "3": # From file PATH
try:
with open(LIST_PATH, "r") as file:
profile_ids_to_query = json.load(file)
if not isinstance(profile_ids_to_query, list):
print(f"Error: Content of {LIST_PATH} is not a JSON list.")
return
print(f"Using {len(profile_ids_to_query)} profile IDs from file: {LIST_PATH}.")
except FileNotFoundError:
print(f"Error: File not found at {LIST_PATH}. Please check the path.")
return
except json.JSONDecodeError:
print(f"Error: Could not decode JSON from {LIST_PATH}. Ensure it's a valid JSON array of strings.")
return
else:
# This case should ideally be caught by the main function's input validation
print("Invalid option for search_proxy_metas. This should not happen.")
return

if not profile_ids_to_query:
print("No profile IDs to query. Exiting proxy meta search.")
return

payload = json.dumps({"ids": profile_ids_to_query})
print(f"Requesting metas for {len(profile_ids_to_query)} profiles.")
response = requests.request("POST", url, headers=HEADERS, data=payload)

if response.status_code != 200:
print(f"Error fetching profile metas: {response.status_code} - {response.text}")
return

try:
response_data = response.json()
except requests.exceptions.JSONDecodeError:
print(f"Error decoding JSON response from profile metas: {response.text}")
return

query_result = []
if response_data and "data" in response_data and "profiles" in response_data["data"]:
for profile_meta in response_data["data"]["profiles"]:
if "parameters" in profile_meta and "proxy" in profile_meta["parameters"]:
proxy_metas = profile_meta["parameters"]["proxy"]
# Optionally, include profile ID with its proxy details
# query_result.append({"profile_id": profile_meta.get("id"), "proxy": proxy_metas})
query_result.append(proxy_metas)
else:
print(f"Warning: Proxy parameters not found for profile ID {profile_meta.get('id', 'N/A')}")
else:
print(f"Unexpected response structure or no profile data in metas response: {response_data}")
return

if not query_result:
print("No proxy details found for the given profile IDs.")
return

proxy_json = json.dumps(query_result, indent=4)
# print(proxy_json) # Optionally print to console

output_filename = "proxy_credentials.json"
try:
with open(output_filename, "w") as json_file:
json_file.write(proxy_json)
print(
f"\nTotal of {len(query_result)} proxies were saved to {output_filename}\n"
)
except IOError as e:
print(f"Error writing to file {output_filename}: {e}")


# Main function
def main():
token = signin()
if token:
HEADERS.update({"Authorization": f"Bearer {token}"})
else:
print("Failed to sign in. Please check credentials and network. Exiting.")
return

option_prompt = (
"\n\nSelect method to provide profile ID list:\n"
" (1) Manual List (uses LIST_MANUAL in script)\n"
" (2) From Profile Search (dynamic, uses profile_search function)\n"
" (3) From file PATH (uses LIST_PATH in script, e.g., profile_ids.json)\n"
"Write selection (1, 2, or 3): "
)

option_call = input(option_prompt)

if option_call not in ["1", "2", "3"]:
print("Invalid selection. Please enter 1, 2, or 3. Exiting.")
return

search_proxy_metas(option_call)

if __name__ == "__main__":
main()

Running the Script

  1. Open your terminal or command prompt.

  2. Navigate to the folder containing proxies_to_json.py and your .env file:

    cd path/to/your/script_folder
  3. Run the script using Python:

    python proxies_to_json.py
  4. Select Input Option: When prompted, choose how the script should obtain the list of profile IDs:

    • Option 1 (Manual List): Uses the LIST_MANUAL Python list hardcoded in the script.
    • Option 2 (From Profile Search): Dynamically fetches profile IDs using the profile_search function.
      • You can adjust the profile_search function's body parameters (e.g., search_text, limit, folder_id if you add it) to refine which profiles are targeted. The current script, by default, searches for up to 100 active profiles.
    • Option 3 (From File Path): Reads profile IDs from the JSON file specified by the LIST_PATH variable in the script.
  5. Check Results: After execution, the script will attempt to save the extracted proxy details in a JSON file named proxy_credentials.json in the same folder. It will also print a summary message to the console.

Example profile_ids.json (for Option 3)

If you use Option (3), ensure your profile_ids.json (or the file specified in LIST_PATH) contains a valid JSON array of profile ID strings:

[
"95f6d02c-xxxx-47c4-b1d4-369801f2a37c",
"48da90d8-xxxx-40a2-8ccb-2d9e7e3eaebb",
"e2f9d96a-xxxx-4439-ae74-10beda6bf109"
]

Understanding the Output: proxy_credentials.json

The proxy_credentials.json file will contain a JSON array. Each object in this array represents the proxy configuration extracted for one of the specified Indigo profiles. The exact fields within each proxy object will depend on the proxy type (e.g., HTTP, HTTPS, SOCKS4, SOCKS5, SSH) and how it's configured in Indigo (e.g., host, port, username, password).

An example of what the output might look like (structure will vary based on your actual proxy settings):

[
{
"type": "http",
"host": "proxy.example.com",
"port": 8080,
"username": "proxy_user_1",
"password": "proxy_password_1"
},
{
"type": "socks5",
"host": "another-proxy.example.org",
"port": 1080,
"username": "",
"password": ""
},
{
"type": "ssh",
"host": "ssh-server.example.net",
"port": 22,
"username": "ssh_user"
// SSH proxy might have 'sshPassword' or 'sshKey' fields
}
]
tip

This script offers a flexible way to automate the retrieval of proxy details from your Indigo profiles, which can be particularly helpful for managing numerous profiles or integrating with other tools and workflows. Remember to handle the output proxy_credentials.json file securely, as it contains sensitive information.