OpenAI computer use
Run OpenAI's computer tool on a SpecStream browser session. The Responses API returns clicks and keystrokes, Playwright runs them in a real Chromium over the session's connect_url, and you send back a screenshot. A session costs $0.10 an hour, charged by the second, so a 5 minute task is under 1 cent of browser time.
What you need
- Python 3.10 or newer.
- An OpenAI API key and a model that supports the
computertool. The script usesgpt-6.1-sol, the model in OpenAI's own example. - A SpecStream account. New accounts start with $10 of credit, no card. Create one.
- 1
1. Install the packages
The OpenAI SDK calls the Responses API, Playwright drives the browser, and httpx calls SpecStream. Playwright connects to the session's browser, so there is no local browser to download and you can skip
playwright install.Terminal - 2
2. Create a SpecStream key and set both keys
In the SpecStream workspace, open Agents & API, choose API keys, then Create API key. A key that opens a browser needs the
finds:spendscope and a spending limit above 0. The limit is the most the key can spend in total, so a small one is enough for a test.Set it next to your model key in the shell that runs the script:
Terminal - 3
3. Save the agent
Save this file as
agent.py. It opens a session, connects Playwright to it, opens the start page, and runs OpenAI's three steps in a loop: send the task, run the returned actions, return a screenshot.The screenshots show the page only, with no address bar, so the script opens
START_URLitself before the first request.agent.py - 4
4. Run it
The script prints the address where you can watch the browser, then the model's answer, then the seconds the session ran and what it cost. Change
START_URLandTASKto your own.Terminal
What the script does
Each part of the loop follows OpenAI's computer use guide.
POST /v1/browser/sessionsopens the browser. The answer'sdataholds the session'sid, itsconnect_urland itslive_url.connect_urlis a WebSocket that speaks the Chrome DevTools Protocol, so Playwright'sconnect_over_cdptakes it as it is. Its token belongs to that one session, so your SpecStream key never reaches the browser side.- The first request sends the task with
tools=[{"type": "computer"}]. The firstcomputer_callmay hold only ascreenshotaction, and the script answers it with the current screen. - Each
computer_callholds an orderedactionsarray. The script runs the actions in order, then takes one screenshot. - The screenshot goes back as a
computer_call_outputwith the samecall_id, as acomputer_screenshotwithdetailset tooriginal, andprevious_response_idcontinues the conversation, so the script keeps no message history. - The loop ends when a response holds no
computer_call, and the script printsoutput_text. POST /v1/browser/sessions/{id}/releaseends the session, also when the script fails, and returns thesecondsit ran andcharged_usd.
How each action reaches the browser
The computer tool can request nine actions. A mouse action may carry a keys array of modifiers, such as Ctrl for a click that opens a new tab. The script holds them down for that one action.
| The model returns | The script runs |
|---|---|
click | page.mouse.click(x, y) with button, where wheel is Playwright's middle |
double_click | page.mouse.dblclick(x, y) |
move | page.mouse.move(x, y) |
scroll | page.mouse.move(x, y), then page.mouse.wheel(scroll_x, scroll_y) |
drag | page.mouse.move to the first point of path, down, move through the other points, up |
keypress | page.keyboard.press with names such as CTRL and ENTER changed to Playwright's Control and Enter |
type | page.keyboard.type(text) |
wait | time.sleep(2) |
screenshot | Nothing: the script takes one after every batch |
If your code still uses computer-use-preview
Many guides still show the preview integration. OpenAI's migration table lists four changes, and the script above is the newer form of each.
| Part | Preview | Now |
|---|---|---|
| Model | computer-use-preview | gpt-6.1-sol |
| Tool | {"type": "computer_use_preview"} with display_width and display_height | {"type": "computer"} |
| Actions | One action on each computer_call | An actions array on each computer_call |
| Truncation | truncation: "auto" required | Not needed |
Screenshots and coordinates
The model gives x and y in the pixels of the screenshot you return. The session's screen is 1280 by 720 unless you send another viewport, the same size as the browser in OpenAI's local example, and Playwright's screenshot is that screen. The script passes the coordinates to the mouse unchanged.
OpenAI recommends detail: "original" on screenshots to keep the resolution and improve click accuracy. A larger viewport gives the model more to read and uses more input tokens for each screenshot.
What a session costs
Browser time is $0.10 an hour, charged by the second. The script drives the session over connect_url, so the clicks and keystrokes add nothing: you pay for the time alone. The $1 per 1,000 actions applies only to steps you send to POST /v1/browser/sessions/{id}/actions.
The model's tokens are billed by OpenAI: each Responses request is charged for its input and output tokens, and screenshots count as image input.
| Session length | Browser time |
|---|---|
| 1 minute | $0.0017 |
| 5 minutes | $0.0083 |
| 10 minutes | $0.0167 |
| 1 hour | $0.10 |
Keep a run inside limits
The model acts on real pages, so bound the run in the session and in the script.
timeout_sis the most seconds the session runs, from 60 to 3,600. Leave it out and the session ends after 300. The script sends 600.allowed_domainslimits the hosts the browser may open, such as["example.com", "*.example.com"]. A page outside them is refused.viewportsets the screen, 1280 by 720 unless you send another, for example{"width": 1280, "height": 800}.- The loop stops after 30 turns. Raise or lower the number in
range(30). - The key's spending limit bounds what all its sessions cost together.
live_urlis a page that shows the browser's screen as it changes. The script prints it at the start, so you can watch the run.- Text on a page is data. OpenAI's guide asks you to treat screen content as untrusted and to confirm purchases, sent data and changes that are hard to undo with a person.
If a run fails
The status of the call tells you which side refused.
| What you see | What to do |
|---|---|
401 from SpecStream | The key is missing or wrong. Check SPECSTREAM_API_KEY. |
402 from SpecStream | The balance or the key's spending limit does not hold the first minute. Add credit or raise the limit. |
403 from SpecStream | The key lacks the finds:spend scope. Create a key that has it. |
429 from SpecStream | The account holds as many open sessions as it may. Release one, or create again after the seconds in Retry-After. |
503 from SpecStream | No browser is free at the moment. Create again after the seconds in Retry-After. |
| An error from OpenAI that names the model or the tool | The project has no access to a model with the computer tool. Check the model's Tools section in OpenAI's models catalog. |
Unsupported action from the script | The model returned an action the handler does not know. Add a branch for it in handle. |
More
SpecStream for OpenAI computer use covers what it does in OpenAI computer use on one page. Every other tool has its guide in Connect your tools. You see the most a request can cost before it starts, and the matches are paid from your balance. Billing has the details. For help, email [email protected].