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.
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
-
Open your terminal or command prompt.
-
Navigate to the folder containing
proxies_to_json.py
and your.env
file:cd path/to/your/script_folder
-
Run the script using Python:
python proxies_to_json.py
-
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'sbody
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.
- You can adjust the
- Option 3 (From File Path): Reads profile IDs from the JSON file specified by the
LIST_PATH
variable in the script.
- Option 1 (Manual List): Uses the
-
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
}
]
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.