Part 1 · Getting started
Your first autonomous task, start to finish
Slapify is a browser agent you give a goal to, not a script. Here is a real run from install to answer, replayed step by step, with what it cost.
Most browser automation asks you to say how: which selector, which click, in which order. Slapify asks you to say what. It reads the page the way a screen reader does, decides what to do next, does it, and keeps going until the goal is met. Along the way it can log in, fill forms, pick from dropdowns, tick checkboxes, upload and download files, switch tabs, remember things between runs, and schedule itself to come back later.
Install and set up
npm install -g slapify
slapify init
init asks which model to use and which browser, then writes a .slapify/ folder. The only thing it needs from you is an API key:
# .slapify/config.yaml
llm:
provider: anthropic
model: claude-sonnet-5
api_key: ${ANTHROPIC_API_KEY}
browser:
headless: true
Any provider the Vercel AI SDK supports works (OpenAI, Google, Mistral, Groq, a local Ollama model), and you can list several: if one is rate-limited or down, the next one takes over.
Give it a goal
To have something we could show end to end, without touching a real shop, we built a tiny demo store called Harbor & Pine. It has six products, a search box, product pages with a size dropdown and a gift-wrap checkbox, and a cart. Then we gave the agent one sentence:
slapify task "Go to the store. Find a waterproof jacket that costs less than $150, \
add it to the cart in size M with gift wrap, and tell me the cart total."
Nothing else: no selectors, no hints about which page has what. Here is exactly what it did. Each frame is a screenshot of the page just before the step runs; the orange box marks the element the agent chose.
A few things worth noticing:
- It checked, and changed its mind. The first jacket it opened was the Summit Shell. It read the page, saw $189, went back and opened the Drizzle Rain Jacket at $129 instead. Nobody told it the first one was too expensive; the goal did.
- It used the right control for the job. The size went through
select_optionand gift wrap throughset_checked, which sets a state rather than toggling it, so running it twice can't untick the box. - It read the result instead of assuming. After adding to cart it opened the cart and read the total from the page: "Cart total: $134", which is $129 plus $5 gift wrap.
How the cost is worked out: we replay the run's log to rebuild what the model saw on every turn (system prompt, tools, goal and history, trimmed the way the harness trims it), count about four characters per token, and price it at list API rates: $2 per million input tokens and $10 per million output for Claude Sonnet 5. Without prompt caching the same run is about $0.17. About 85% of each prompt is identical to the previous one, which is what caching makes cheap.
How it sees a page
The agent doesn't look at pixels by default. It asks for the page's accessibility tree: the same list of buttons, links, inputs and headings a screen reader announces, each with a short ref.
- link "Harbor & Pine" [ref=e1]
- textbox "Search products" [ref=e2]
- button "Search" [ref=e3]
- combobox [ref=e4]: Choose a size
- checkbox "Gift wrap (+$5)" [ref=e5]
- button "Add to cart" [ref=e8]
Refs are what it acts on: select_option(e4, "M"), set_checked(e5, true), click(e8). For reading, it calls get_page_text(), because the tree lists controls but not body copy, and get_links() when it needs a real URL rather than a guess. When text isn't enough (a chart, a CAPTCHA, an image-only post) turn on vision: true and it can look at a screenshot too.
What it can do
| Area | Tools |
|---|---|
| Navigate and read | navigate, get_page_state, get_page_text, get_links, scroll, go_back, screenshot |
| Act like a person | click, double_click, hover, drag, type, press, select_option, set_checked |
| Files and tabs | upload_file (only from an uploads folder), download_file, list_tabs, switch_tab, close_tab |
| Accounts | Saved credential profiles, login-form filling, persistent browser profiles, CAPTCHA solving |
| Time and memory | remember/recall across runs, schedule itself on a cron, sleep_until |
| People | ask_user for a 2FA code, status_update, and a Telegram bridge to steer it from your phone |
| Output | Structured JSON against a schema, an HTML report of the whole session |
From code
The same agent is a library. createAgent() reads .slapify/config.yaml if there is one, and anything you pass inline is laid over it:
import { createAgent } from "slapify";
const agent = createAgent({ stealth: true });
// run to completion
const run = await agent.run("Find a waterproof jacket under $150 on the store and add it in size M");
console.log(run.finalSummary);
// or watch it work
for await (const event of agent.stream("Check the order status for #4821")) {
if (event.type === "tool_start") console.log(event.toolName, event.args);
}
// and come back to it later, memory included
await agent.resume(run.id, "Now remove gift wrap and tell me the new total");
Want data rather than prose? Pass a JSON schema and it writes conforming output:
const run = await agent.run("List every jacket in the store with its price", {
schema: { type: "array", items: { type: "object", properties: { name: { type: "string" }, price: { type: "number" } } } },
outputFile: "jackets.json",
});
Where to go next
A one-minute task is the easy case. The rest of this series is about the hard one: an agent that runs for days on a real website, unattended. Part 2 is the story of building exactly that, and everything that broke along the way.