reversing-network
Reversing Network (Browser → HTTP)
Replace browser automation with faster, more reliable HTTP requests by reverse-engineering the underlying API with robomotion-browser-mcp network capture.
Pairs with: exploring-browser — capture traffic there during exploration, then come here to convert.
When to Use This
| Use browser automation | Use network reversal |
|---|---|
| Site has heavy JS rendering | Site's data comes from API calls |
| No clear API endpoint | API endpoint is discoverable via DevTools |
| Login requires JS execution | Login returns a token in response headers/body |
| Site changes selectors frequently | API is stable and versioned |
Step 1: Capture Network Traffic with Browser MCP
Open a browser with network capture enabled, then perform the target actions:
1. browser_open(stealth: true)
2. browser_start_network_capture(url_filter: "api.", capture_body: true)
3. browser_navigate(url: "https://example.com/search")
4. browser_snapshot() — read the page to find interactive elements
5. browser_click / browser_type — perform the user action (search, login, etc.)
6. browser_get_requests(method: "POST") — list captured API calls
7. browser_get_request_response(request_id: "...") — inspect a specific pair
Use browser_snapshot() between actions to see the page state. Repeat click/type/snapshot until the target API calls appear in browser_get_requests.
Step 2: Analyze the Captured Request
From the JSON returned by browser_get_request_response, inspect:
- Request:
request.method,request.url,request.headers,request.body - Response:
response.status,response.headers,response.body,response.mimeType
Identify:
- Endpoint URL — often contains version (
/api/v2/products) - Required headers — Authorization, X-API-Key, cookies, Content-Type
- Request body format — JSON, form-data, GraphQL
- Authentication flow — does login return a Bearer token?
Step 3: Build the HTTP Flow
import { flow, Message, Custom, Credential } from '@robomotion/sdk';
const myFlow = flow.create('main', 'API Scraper', (f) => {
f.node('start', 'Core.Trigger.Inject', 'Start', {})
// Step 1: Authenticate (if needed)
.then('auth', 'Core.Net.HttpRequest', 'Login', {
optUrl: Custom('https://api.example.com/auth/login'),
optMethod: 'post',
inBody: Custom(JSON.stringify({ username: '...', password: '...' })),
inCustomHeaders: [{ scope: 'Custom', name: { name: 'Content-Type', value: 'application/json' } }],
outBody: Message('auth_body'),
outStatus: Message('auth_status')
})
// Step 2: Extract token from response
.then('token', 'Core.Programming.Function', 'Extract Token', {
func: `
msg.bearer_token = 'Bearer ' + msg.auth_body.token;
return msg;
`
})
// Step 3: Build headers object with token
.then('headers', 'Core.Programming.Function', 'Build Headers', {
func: `
msg.headers = {
'Authorization': msg.bearer_token,
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0'
};
return msg;
`
})
// Step 4: Call the actual data API
.then('api', 'Core.Net.HttpRequest', 'Get Data', {
optUrl: Custom('https://api.example.com/products?page=1'),
optMethod: 'get',
inHeaders: Message('headers'),
outBody: Message('api_body'),
outStatus: Message('api_status')
})
// Step 5: Parse and process
.then('parse', 'Core.Programming.Function', 'Parse Response', {
func: `
msg.products = msg.api_body.items;
return msg;
`
})
.then('stop', 'Core.Flow.Stop', 'Done', {});
});
myFlow.start();
Step 4: Handle Pagination
For paginated APIs, use the loop pattern:
// ForEach over page numbers or use cursor/offset from response
f.node('loop', 'Core.Programming.ForEach', 'Each Page', {
optInput: Message('page_numbers'), // [1, 2, 3, ...]
optOutput: Message('page_num')
})
// ... make API call with page_num ...
f.node('goto', 'Core.Flow.GoTo', 'Next', {
optNodes: { ids: ['LABEL_ID'], type: 'goto', all: false }
})
Key Rules
- Always verify the API response format before building the full flow
- Store credentials in vault — never hardcode API keys or tokens
- Handle rate limits — add
delayBeforeor retry loops for 429 responses - Check token expiry — some tokens expire; add refresh logic if needed
- Core.Net.HttpRequest is built-in — no extra dependency needed (it's in the
Corepackage)
Common HTTP Node Properties
Verify exact names with robomotion describe node Core.Net.HttpRequest:
| Property | Value |
|---|---|
| URL (Option) | optUrl: Custom('https://...') or Message('url') |
| Method (Option) | optMethod: 'get' | 'post' | 'put' | 'delete' | 'patch' (lowercase enum) |
| Headers (Input) | inHeaders: Message('headers') (key-value object) or inCustomHeaders: [{ scope: 'Custom', name: { name: 'X', value: 'Y' } }] |
| Body (Input) | inBody: Custom(JSON.stringify({...})) or Message('body') |
| Response body (Output) | outBody: Message('resp_body') — parsed JSON when Content-Type: application/json, otherwise string |
| Response status (Output) | outStatus: Message('status') |
| Response headers (Output) | outHeaders: Message('resp_headers') |
Cleanup
Always call browser_stop_network_capture and browser_close when done capturing, even if the flow build fails. Leaving the browser open wastes resources and can block subsequent runs.
More from robomotionio/agent-skills
running-flow
Validates locally (`robomotion validate`) then executes a Robomotion flow on a robot (`robomotion run <flow-dir>`), tailing the agent-mode JSONL session log to drive a validate → run → observe → fix loop with bounded retries. Use when the user says "run the flow", "start on robot X", "trigger this on the robot", "test on a robot", or "deploy and run".
18creating-flow
Creates Robomotion automation flows with the @robomotion/sdk TypeScript builder. Owns the full lifecycle: requirements → plan → build → validate → deploy. Also use when the user has a plan ready and wants the flow code written.
18validating-flow
Validates a compiled Robomotion flow against pspec schemas via `robomotion validate <flow-dir>`. Exits 0 on clean, 1 on error with node-by-node report on stderr; no stdout output (composes in shell pipelines). Use when the user says "validate this flow", "check the flow", "is this correct", or before running. Does NOT run the flow — for behavioral tests use testing-flow.
18testing-flow
Runs and authors behavioral tests for Robomotion flows using @robomotion/sdk/testing. Use when the user says "test the flow", "write tests for main.ts", "mock this service", "check branch coverage", or when a flow needs regression tests before a change. For pspec schema validation, use validating-flow instead.
18searching-packages
Finds Robomotion packages, nodes, and templates via the `robomotion` CLI, which is backed by Bleve full-text search with fuzzy matching and semantic expansion. Use when the user asks to find a package, explore templates, discover what nodes exist for a task, or check exact property names before writing a flow.
18exploring-browser
Explores a website interactively via the robomotion-browser-mcp server to discover selectors, record action sequences, capture network traffic, and produce a JSON flow sequence that maps to Robomotion SDK TypeScript. Use when the user says "explore this page", "find the selector for X", "record the login flow", "what API does this page use", or before writing ANY `Core.Browser.*` flow. Pairs with `reversing-network` when the captured traffic reveals a clean API.
18