What the GoLogin API Actually Does
The GoLogin API is two layers stacked on each other: a REST API at https://api.gologin.com that manages profiles, workspaces and proxies with a Bearer token, and an SDK that launches one saved profile and returns its local debugger address so Selenium, Playwright or Puppeteer can drive that browser. Both layers start at the Professional 100 tier — not on Free, and not on Professional 10, 25 or 50.
📌 TL;DR Executive Summary
- Core Takeaway: REST calls at https://api.gologin.com manage profile records with a Bearer JWT;
gl.start()launches the browser and returns a host:port address you hand to Selenium, Playwright or Puppeteer. - Key Risk/Challenge: Access is plan-gated (Professional 100 and above), and most failures are a profile name passed where the profile ID is required, or a ChromeDriver that does not match the Orbita Chromium build.
- Recommended Solution: Keep the token in an environment variable, handle 401 and 429 explicitly, and pin ChromeDriver with
get_chromium_version()before the first session starts.
Layer 1: the REST API manages records, not browsers
A REST call tells you what exists in the account. Nothing is running afterwards. The documented surface is narrow: /browser/v2 for every profile across every workspace, /workspaces/{wid}/profiles for a single workspace, plus /deleted-profiles/v2, /proxy/v2 and /workspaces. That is enough for inventory, bulk edits and wiring profile IDs into your own scripts, and it is where most tutorials about the GoLogin API stop.
Layer 2: the SDK starts a browser and hands you the address
The SDK is the part that matters for automation. gl.start() launches the profile’s Orbita Chromium build and returns a debugger address such as 127.0.0.1:53421. Your framework attaches to that address, so the browser you control is the profile itself — its cookies, storage and fingerprint settings included. gl.stop() shuts it down.
Keeping the layers apart prevents the most common confusion in this workflow: a successful GET /browser/v2 proves your token works, not that a browser is available for Selenium to attach to. The two checks are independent, and you need both.
Prerequisites Before You Write a Line of Code
- A plan that includes the API. REST API and SDKs are included from Professional 100 upward, and on all Business, Enterprise and Custom plans. Free and Professional 10/25/50 do not include them.
- An API token generated in app.gologin.com under Settings → API (the direct path is
/#/personalArea/TokenApi). - Python 3.9 or newer and a desktop session where a browser can run. Orbita downloads on first launch and is reused afterwards.
- One saved profile whose ID you can copy. You need the ID, not the display name.
- Outbound access to api.gologin.com and a free local port range for the debugger socket.
Install the packages
- Create and activate a virtual environment:
python3 -m venv .venv, thensource .venv/bin/activate(Windows:.venv\Scripts\activate). - Install the dependencies:
pip install gologin selenium webdriver-manager requests. - Store the token:
export GOLOGIN_TOKEN="..."in bash, or$env:GOLOGIN_TOKEN="..."in PowerShell.
The Python package is published as gologin on PyPI, with 2026.6.24 as the current release. A Node SDK exists as well and returns a websocket URL for the same purpose. This walkthrough stays in Python because the helper methods for proxies, cookies and user agents are best documented there.
Which plan actually unlocks the API
Check this first, because no amount of correct code fixes a plan without API access.
| GoLogin plan | REST API & SDKs | API rate limit |
|---|---|---|
| Free | Not included | — |
| Professional 10 / 25 / 50 | Not included | — |
| Professional 100 and above | Included | 300 requests/min |
| Business | Included | 500 requests/min |
| Enterprise | Included | 800 requests/min |
| Custom | Included | 1,200 requests/min |
Three billing details are easy to miss. New accounts get a 7-day free trial, but trial proxy traffic is not included, and API access still follows the tier — a trial on a small plan will not expose the REST endpoints. Every paid plan includes 2 GB of residential proxy traffic, and annual billing is roughly half the monthly price. If the gating itself is what you are weighing up, our GoLogin alternative comparison maps what changes at each tier.
Generate and store the token
- Sign in at app.gologin.com.
- Open Settings → API, or paste
/#/personalArea/TokenApiafter the domain. - Copy the token once and put it straight into your environment variable.
- Rotate it if it ever appears in a screenshot, a chat message or a commit.
Step 1: Read Your Profiles With the REST API
Start with the endpoint you will call most. GET /browser/v2 returns every profile in the account, and each object carries the id your script needs later. Send the token as a Bearer header — not as a query parameter, and without duplicating the word “Bearer” if you copied it along with the token.
How Send.win Helps With Gologin Api
Send.win is a browser profile manager for professionals and teams: every account gets its own isolated browser profile.
- Isolated profiles – separate cookies, storage and sessions per profile
- Fingerprint protection – each profile keeps its own consistent browser fingerprint, so profiles never share one browser identity
- Desktop app + cloud browser – native app for Windows, macOS and Linux, or run profiles in the cloud with no install
- Residential proxies included – on Pro and Team, with timezone and locale matched to the proxy
- Team sharing – share a signed-in profile with a teammate without sharing the password
Try the free cloud demo — no install — or download the desktop app. Paid plans start at $19/month, and your first card purchase is covered by a 7-day money-back guarantee (see pricing).
import os
import time
import requests
TOKEN = os.environ["GOLOGIN_TOKEN"]
BASE = "https://api.gologin.com"
HEADERS = {"Authorization": f"Bearer {TOKEN}", "Accept": "application/json"}
def get_json(path, tries=3):
"""GET with explicit handling for auth failures and rate limits."""
for attempt in range(tries):
resp = requests.get(f"{BASE}{path}", headers=HEADERS, timeout=30)
if resp.status_code == 401:
raise SystemExit("401: token rejected - regenerate it in Settings, API tab")
if resp.status_code == 429:
pause = int(resp.headers.get("Retry-After", 2 ** attempt))
time.sleep(pause)
continue
resp.raise_for_status()
return resp.json()
raise RuntimeError(f"still rate limited after {tries} attempts: {path}")
profiles = get_json("/browser/v2")
print(f"{len(profiles)} profiles in this account")
for p in profiles[:5]:
print(p["id"], "|", p["name"], "|", p.get("os", "?"))
Three behaviours are worth designing around. /browser/v2 spans every workspace, so if your team separates client work by workspace, call /workspaces/{wid}/profiles and skip the client-side filter. The response is the full list, so filter and slice in Python rather than assuming a page parameter. And treat 401 and 429 differently: a 401 is a token or plan problem that will never fix itself, while a 429 is a pacing problem a short sleep usually clears.
Keep your own name-to-ID map in a small local file. Scripts that re-list the whole account on every run spend requests against your per-minute allowance for nothing. If you want a wider picture of how profile state, cookies and fingerprint settings are exposed over HTTP, the browser profile API guide walks through the object model.
profiles.json once a day and refresh on demand. A 300-request-per-minute allowance sounds generous until a loop over 200 profiles calls the list endpoint on every iteration.
Step 2: Launch a Profile With the Python SDK
With an ID in hand, the SDK does the launch. Pass token and profile_id to the constructor, call start(), and store the returned address.
import os
from gologin import GoLogin
PROFILE_ID = "66f1c0a1b2c3d4e5f6071829" # from /browser/v2 - not the profile name
gl = GoLogin({
"token": os.environ["GOLOGIN_TOKEN"],
"profile_id": PROFILE_ID,
})
debugger_address = gl.start() # e.g. "127.0.0.1:53421"
print(debugger_address)
# ... attach Selenium or Playwright here ...
gl.stop()
start() is synchronous and slow on the first run, because Orbita is downloaded and unpacked before the window opens. Later launches reuse the downloaded build instead of fetching it again. The returned string is a plain host:port pair, which is exactly what Selenium’s debuggerAddress capability and Playwright’s connect_over_cdp both expect.
Four optional start parameters come up often. executablePath pins a specific Orbita build instead of letting the SDK fetch one. extra_params passes Chromium switches such as --headless. uploadCookiesToServer defaults to false. writeCookesFromServer defaults to true — note the misspelling in the package; check the current source before relying on it, because a mistyped keyword argument is silently ignored in some versions.
Step 3: Attach Selenium to the Debugger Address
Selenium does not start a browser here. It attaches to the one the SDK already opened, using the debuggerAddress experimental option. The one hard requirement is that ChromeDriver matches the Chromium build behind that address.
import os
from gologin import GoLogin
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
PROFILE_ID = "66f1c0a1b2c3d4e5f6071829" # id field from /browser/v2
gl = GoLogin({"token": os.environ["GOLOGIN_TOKEN"], "profile_id": PROFILE_ID})
version = gl.get_chromium_version() # the Orbita Chromium version
service = Service(ChromeDriverManager(driver_version=version).install())
options = Options()
options.add_experimental_option("debuggerAddress", gl.start())
driver = webdriver.Chrome(service=service, options=options)
driver.get("https://example.com")
print(driver.title)
driver.quit()
gl.stop()
get_chromium_version() is the call that saves an afternoon. Without it, webdriver-manager installs the driver for the newest stable Chrome, Orbita reports a different major version, and the session dies with SessionNotCreatedException before your first get(). Pinning the driver version makes the pair match, and it keeps matching after an Orbita update.
Order matters at the end of the script too. driver.quit() before gl.stop(): quitting the driver releases the connection, stopping the SDK shuts the profile’s browser down. Reversed, you can leave a stray driver process holding the port and the next launch fails with an address already in use.
ChromeDriverManager() with no arguments always fetches the latest driver. Always pass driver_version=gl.get_chromium_version(), and cache the downloaded driver so CI runs do not re-download on every job.
Playwright over the same address
Playwright connects over CDP, so the SDK call is identical and only the client changes. Keep the profile’s first page context if you want the session’s existing cookies to be visible to your script.
import os
from gologin import GoLogin
from playwright.sync_api import sync_playwright
PROFILE_ID = "66f1c0a1b2c3d4e5f6071829" # id field from /browser/v2
gl = GoLogin({"token": os.environ["GOLOGIN_TOKEN"], "profile_id": PROFILE_ID})
address = gl.start()
try:
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(f"http://{address}")
context = browser.contexts[0]
page = context.pages[0] if context.pages else context.new_page()
page.goto("https://example.com")
print(page.title())
browser.close()
finally:
gl.stop()
Step 4: Create and Configure Profiles From Code
Two creation methods cover most needs. createProfileRandomFingerprint({"os": "lin", "name": "..."}) builds a profile with a consistent set of fingerprint values for Linux ("lin"), Windows ("win") or macOS ("mac"). createProfileWithCustomParams() lets you set specific navigator fields — userAgent, resolution, language, platform, hardwareConcurrency, deviceMemory, maxTouchPoints. The complete parameter list sits at api.gologin.com/docs.
import os
from gologin import GoLogin
gl = GoLogin({"token": os.environ["GOLOGIN_TOKEN"]})
profile = gl.createProfileWithCustomParams({
"name": "QA checkout - en-US desktop",
"os": "lin",
"navigator": {
"userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
"resolution": "1920x1080",
"language": "en-US",
"platform": "Linux x86_64",
"hardwareConcurrency": 8,
"deviceMemory": 8,
"maxTouchPoints": 0,
},
})
profile_id = profile["id"]
gl.setProfileId(profile_id) # subsequent start() targets this profile
gl.changeProfileProxy(profile_id, {
"mode": "http",
"host": "proxy.example.com",
"port": 8000,
"username": "user",
"password": "pass",
})
gl.addCookiesToProfile(profile_id, [
{
"name": "session_id",
"value": "abc123",
"domain": ".example.com",
"path": "/",
"secure": True,
"httpOnly": True,
},
])
Four helper methods do the repetitive work. addGologinProxyToProfile(profileId, countryCode) attaches a GoLogin residential exit in one call when you do not want to supply host and port yourself. changeProfileProxy() takes your own HTTP or SOCKS5 endpoint in the shape shown above. addCookiesToProfile() writes a list of cookie objects so a profile starts already logged in. updateUserAgentToLatestBrowser([ids]) and refreshProfilesFingerprint([ids]) are maintenance calls — run them when you rebuild a profile, not mid-session, because both change what the profile presents on its next launch. The SDK also sends anonymous error telemetry unless you set DISABLE_TELEMETRY=true, so add that to the same environment file as the token, especially on shared build machines.
If proxy wiring is the part you keep redoing by hand, the step-by-step guide on how to set up a GoLogin proxy covers modes, credentials and the checks that catch a dead exit before it reaches a session.
One boundary worth stating plainly: create profiles only for accounts you own or are authorised to manage, and follow each platform’s terms on how many accounts one person or business may hold. The API makes profile management faster; it does not change what you are allowed to do with those profiles.
Common Errors and How to Fix Them
Almost every failure in this workflow falls into one of six buckets. The table maps the symptom to the cause before you start adding print statements.
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 on every request | Token truncated, taken from another account, or the header already includes “Bearer” | Regenerate in Settings → API; send Authorization: Bearer <token> exactly once |
| Endpoints refuse to work on a paid plan | Plan does not include REST API and SDKs (Free, Professional 10/25/50) | Move to Professional 100 or above, or Business |
start() cannot find the profile |
Profile name passed instead of the profile ID | Read id from /browser/v2; names are not unique |
SessionNotCreatedException |
ChromeDriver version differs from the Orbita Chromium build | ChromeDriverManager(driver_version=gl.get_chromium_version()) |
| 429 Too Many Requests | Request pace above the plan limit | Honour Retry-After; 300 RPM on Professional, 500 Business, 800 Enterprise, 1,200 Custom |
| Browser closes seconds after launch | Profile already open in the desktop app or another script; or a stale executablePath |
Close the other session; pin a fresh Orbita path |
Two more that do not fit the table cleanly. A keyword argument that does nothing is usually the writeCookesFromServer spelling — the package ships it with the typo, so copy the name from the installed source rather than from memory. And a driver that connects but shows an empty page usually means the SDK’s browser is fine and your driver.get() ran against the wrong window handle; check driver.window_handles before assuming the launch failed. On pacing, log the status and the Retry-After header for every non-200 and back off exponentially when the header is missing — a batch job that creates a few hundred profiles will exhaust 300 requests per minute long before it finishes if you fire in a tight loop.
The Full Script, End to End
Here is the whole flow in one file: resolve a profile by name over REST, launch it through the SDK, attach Selenium with a matching driver, read one page, and clean up in the right order. It opens example.com — swap in whatever page your own test or QA run needs.
"""Launch a saved GoLogin profile under Selenium and read one page title."""
import os
import time
import requests
from gologin import GoLogin
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
TOKEN = os.environ["GOLOGIN_TOKEN"]
BASE = "https://api.gologin.com"
HEADERS = {"Authorization": f"Bearer {TOKEN}", "Accept": "application/json"}
def list_profiles(tries=3):
for attempt in range(tries):
resp = requests.get(f"{BASE}/browser/v2", headers=HEADERS, timeout=30)
if resp.status_code == 401:
raise SystemExit("401: check the token came from the Settings API tab")
if resp.status_code == 429:
time.sleep(int(resp.headers.get("Retry-After", 2 ** attempt)))
continue
resp.raise_for_status()
return resp.json()
raise RuntimeError("rate limited after 3 attempts")
def profile_id_by_name(name):
for profile in list_profiles():
if profile["name"] == name:
return profile["id"]
raise SystemExit(f"no profile named {name!r}")
def main():
profile_id = profile_id_by_name("QA checkout - en-US desktop")
gl = GoLogin({"token": TOKEN, "profile_id": profile_id})
driver = None
started = False
try:
service = Service(
ChromeDriverManager(driver_version=gl.get_chromium_version()).install()
)
options = Options()
options.add_experimental_option("debuggerAddress", gl.start())
started = True
driver = webdriver.Chrome(service=service, options=options)
driver.get("https://example.com")
print("title:", driver.title)
finally:
if driver is not None:
driver.quit()
if started:
gl.stop()
if __name__ == "__main__":
main()
The finally block is the part people skip in prototypes and regret in CI: without it, a failing assertion leaves an Orbita process and a ChromeDriver process alive, and the next run collides with both. The started flag matters too — calling gl.stop() after a launch that never succeeded can raise a second error on top of the first and bury the real message.
When You Do Not Need the API at All
Plenty of profile work never calls an endpoint. If your day is opening a client’s profile, signing in, handing it to a colleague and closing it, the API adds a dependency without removing a task.
That is the gap Send.win sits in. It is a browser profile manager with isolated profiles that each keep their own cookies, storage, sessions, fingerprint settings and proxy, available as the Sendwin Browser desktop app for Windows, macOS and Linux or as a cloud browser running on Send.win’s EU server in Helsinki. You can share a profile with a paid teammate and it opens already signed in, with no password changing hands. It has no API, SDK, headless mode or Selenium/Playwright integration on any plan, so it is the wrong tool for the script above and a reasonable one for hand-driven, shared work. The Send.win vs GoLogin breakdown covers where the two overlap and where they do not.
🏆 Send.win Verdict
Everything in this walkthrough belongs to GoLogin: the REST endpoints, the launch helper and the debugger address are GoLogin’s, and they are the right answer when you need repeatable browser runs against profiles you own or are authorised to manage.
Send.win is not the tool for that job. What it covers is the hand-driven half of multi-account work: isolated profiles that each keep their own cookies, storage, sessions, fingerprint settings and proxy, residential proxies on Pro and Team, cloud sync across devices, and profile sharing that opens a client’s session already signed in so nobody swaps a password over chat.
If your day is opening a profile, signing in, handing it to a colleague and closing it, that is the workflow it is built for. When a test harness has to drive the browser, GoLogin’s stack is the one to set up.
See Send.win plans — Pro is $19/mo or $83.88/yr, Team is $49/mo or $251.88/yr, and the free cloud demo gives you 10 minutes a day with nothing to install.
Frequently Asked Questions
How do I get a GoLogin API token?
Sign in at app.gologin.com, open Settings → API (the direct path is /#/personalArea/TokenApi), generate the token and copy it once. Store it as an environment variable rather than in your code. It authenticates the whole account, so rotate it if it is ever exposed.
Which GoLogin plans include API access?
REST API and SDKs are not included on Free or on Professional 10, 25 and 50. They are included from Professional 100 upward and on all Business, Enterprise and Custom plans. Rate limits scale with the tier: 300 requests per minute on Professional, 500 on Business, 800 on Enterprise, 1,200 on Custom.
What is the base URL and auth header for the GoLogin API?
The base URL is https://api.gologin.com and every request carries Authorization: Bearer <token>. There is no query-string key option. Profile, workspace, proxy and deleted-profile endpoints all sit under that same base and header.
Why does start() fail when I pass the profile name?
The SDK constructor expects the profile ID, not the display name. Profile names are not unique, so a name cannot identify one profile reliably. Read the id field from /browser/v2 and pass that string instead.
Does GoLogin have a Python SDK, or only Node?
Both exist. The Python package installs with pip install gologin and is currently at 2026.6.24; the Node module wraps the same create, launch and stop calls and returns a websocket URL for Puppeteer, Selenium or Playwright. The Python package additionally exposes get_chromium_version(), proxy and cookie helpers, and user-agent refresh helpers.
How do I avoid hitting the rate limit in a batch job?
Read the Retry-After response header and sleep for that long, then retry with exponential backoff when the header is absent. Cache the profile list locally instead of re-fetching it inside loops, and spread bulk profile creation across minutes rather than firing it in one burst.
Is the Web Unlocker the same API?
No. The Web Unlocker is a separate product at parsing.webunlocker.gologin.com/v1 with its own apikey header, and the key is issued by contacting GoLogin rather than generated in Settings → API. It is a fetching endpoint, not a profile endpoint, so check each site’s terms before pointing it at anything.
Can I run the launched browser headless?
Yes — pass extra_params=["--headless"] to start(). Pin executablePath as well in anything you keep, because the automatic Orbita download can change between runs and a changed build means a changed ChromeDriver requirement.