Documentation Index
Fetch the complete documentation index at: https://mintlify.com/jo-inc/camofox-browser/llms.txt
Use this file to discover all available pages before exploring further.
Search macros are URL shortcuts that expand search queries into full URLs for popular sites. Instead of manually constructing search URLs with proper encoding, use macros like @google_search or @youtube_search.
What are search macros?
Macros simplify navigation by handling URL construction and query encoding:
# Without macro (manual URL encoding)
POST /tabs/:tabId/navigate
{
"userId": "agent1",
"url": "https://www.google.com/search?q=machine%20learning%20tutorial"
}
# With macro (automatic encoding)
POST /tabs/:tabId/navigate
{
"userId": "agent1",
"macro": "@google_search",
"query": "machine learning tutorial"
}
Both produce identical results, but macros eliminate manual encodeURIComponent() calls and URL structure knowledge.
Why macros exist
From practical experience building AI browser agents:
- Avoid encoding bugs: LLMs frequently forget to encode special characters (spaces, &, #, etc.)
- Site-specific URL structures: Each site has different query param names (
q=, search_query=, keywords=)
- API format changes: When Reddit switches from HTML to JSON, only the macro needs updating
- Prompt brevity: Shorter tool calls = more context for reasoning
Macros are optional - you can always use the url parameter directly if you prefer full control.
Complete macro list
From lib/macros.js:1-16, here are all 14 supported macros:
| Macro | Site | Expands to |
|---|
@google_search | Google | https://www.google.com/search?q=... |
@youtube_search | YouTube | https://www.youtube.com/results?search_query=... |
@amazon_search | Amazon | https://www.amazon.com/s?k=... |
@reddit_search | Reddit | https://www.reddit.com/search.json?q=...&limit=25 |
@reddit_subreddit | Reddit | https://www.reddit.com/r/....json?limit=25 |
@wikipedia_search | Wikipedia | https://en.wikipedia.org/wiki/Special:Search?search=... |
@twitter_search | Twitter/X | https://twitter.com/search?q=... |
@yelp_search | Yelp | https://www.yelp.com/search?find_desc=... |
@spotify_search | Spotify | https://open.spotify.com/search/... |
@netflix_search | Netflix | https://www.netflix.com/search?q=... |
@linkedin_search | LinkedIn | https://www.linkedin.com/search/results/all/?keywords=... |
@instagram_search | Instagram | https://www.instagram.com/explore/tags/... |
@tiktok_search | TikTok | https://www.tiktok.com/search?q=... |
@twitch_search | Twitch | https://www.twitch.tv/search?term=... |
Usage in navigate endpoint
From server.js:872-934, the navigate endpoint accepts both url and macro:
POST /tabs/:tabId/navigate
{
"userId": "agent1",
"macro": "@youtube_search",
"query": "python tutorial"
}
Server-side expansion:
let targetUrl = url;
if (macro) {
targetUrl = expandMacro(macro, query) || url;
}
if (!targetUrl) throw new Error('url or macro required');
Macro takes precedence - if both macro and url are provided, macro is used and url serves as fallback.
Real expansion examples
Google search
Input:
{"macro": "@google_search", "query": "best restaurants near me"}
Expands to:
https://www.google.com/search?q=best%20restaurants%20near%20me
YouTube search
Input:
{"macro": "@youtube_search", "query": "how to bake bread"}
Expands to:
https://www.youtube.com/results?search_query=how%20to%20bake%20bread
Amazon search
Input:
{"macro": "@amazon_search", "query": "wireless headphones"}
Expands to:
https://www.amazon.com/s?k=wireless%20headphones
Wikipedia search
Input:
{"macro": "@wikipedia_search", "query": "quantum computing"}
Expands to:
https://en.wikipedia.org/wiki/Special:Search?search=quantum%20computing
LinkedIn search
Input:
{"macro": "@linkedin_search", "query": "software engineer"}
Expands to:
https://www.linkedin.com/search/results/all/?keywords=software%20engineer
Reddit JSON behavior
Reddit macros return JSON instead of HTML, enabling direct parsing without snapshot/scraping.
@reddit_search
From lib/macros.js:5:
'@reddit_search': (query) => `https://www.reddit.com/search.json?q=${encodeURIComponent(query || '')}&limit=25`
Example:
POST /tabs/:tabId/navigate
{"userId": "agent1", "macro": "@reddit_search", "query": "best programming languages"}
GET /tabs/:tabId/snapshot?userId=agent1
Returns raw JSON response:
{
"kind": "Listing",
"data": {
"children": [
{
"kind": "t3",
"data": {
"title": "What's the best programming language to learn in 2024?",
"selftext": "I'm a beginner and...",
"url": "https://reddit.com/r/learnprogramming/comments/abc123",
"score": 456,
"num_comments": 89
}
}
]
}
}
@reddit_subreddit
From lib/macros.js:6:
'@reddit_subreddit': (query) => `https://www.reddit.com/r/${encodeURIComponent(query || 'all')}.json?limit=25`
Fetch hot posts from a subreddit:
POST /tabs/:tabId/navigate
{"userId": "agent1", "macro": "@reddit_subreddit", "query": "programming"}
Expands to:
https://www.reddit.com/r/programming.json?limit=25
Returns JSON listing of top 25 posts in r/programming.
Use page.evaluate() to extract specific fields from the JSON instead of parsing the entire snapshot.
Implementation details
Macro expansion function
From lib/macros.js:18-21:
function expandMacro(macro, query) {
const macroFn = MACROS[macro];
return macroFn ? macroFn(query) : null;
}
- Returns
null if macro doesn’t exist (triggers fallback to url parameter)
- Query defaults to empty string if undefined
- Uses native
encodeURIComponent() for safety
Available macros lookup
From lib/macros.js:23-25:
function getSupportedMacros() {
return Object.keys(MACROS);
}
For programmatic discovery:
const { getSupportedMacros } = require('./lib/macros');
console.log(getSupportedMacros());
// ['@google_search', '@youtube_search', ...]
Special characters handling
Macros automatically handle special characters:
Spaces
# Query with spaces
{"macro": "@google_search", "query": "new york weather"}
# Expands to: ?q=new%20york%20weather
Ampersands
# Query with &
{"macro": "@amazon_search", "query": "pots & pans"}
# Expands to: ?k=pots%20%26%20pans
Unicode
# Query with emoji
{"macro": "@twitter_search", "query": "🔥 trending"}
# Expands to: ?q=%F0%9F%94%A5%20trending
Quotes
# Query with quotes
{"macro": "@google_search", "query": '"exact phrase search"'}
# Expands to: ?q=%22exact%20phrase%20search%22
Error handling
Unknown macro
If macro doesn’t exist:
POST /tabs/:tabId/navigate
{
"userId": "agent1",
"macro": "@nonexistent",
"query": "test",
"url": "https://google.com" # Fallback
}
Behavior: Falls back to url parameter. If no url provided, returns error: “url or macro required”.
Empty query
From lib/macros.js:2:
'@google_search': (query) => `https://www.google.com/search?q=${encodeURIComponent(query || '')}`
Empty queries are allowed:
{"macro": "@google_search", "query": ""}
# Expands to: https://www.google.com/search?q=
This navigates to the search homepage.
Workflow examples
Multi-site research
# 1. Google search
POST /tabs/:tabId/navigate
{"userId": "researcher", "macro": "@google_search", "query": "climate change effects"}
GET /tabs/:tabId/snapshot?userId=researcher
# Parse top result link (e.g., e5)
POST /tabs/:tabId/click
{"userId": "researcher", "ref": "e5"}
# 2. YouTube search
POST /tabs/:tabId2/navigate
{"userId": "researcher", "macro": "@youtube_search", "query": "climate change documentary"}
GET /tabs/:tabId2/snapshot?userId=researcher
# Get video thumbnails and titles
# 3. Reddit discussion
POST /tabs/:tabId3/navigate
{"userId": "researcher", "macro": "@reddit_search", "query": "climate change"}
GET /tabs/:tabId3/snapshot?userId=researcher
# Parse JSON directly - no need for element refs
E-commerce price comparison
# Search Amazon
POST /tabs/:tabId1/navigate
{"userId": "shopper", "macro": "@amazon_search", "query": "coffee maker"}
GET /tabs/:tabId1/snapshot?userId=shopper
# Extract prices from snapshot
# Search alternative site (no macro - use URL)
POST /tabs/:tabId2/navigate
{"userId": "shopper", "url": "https://www.target.com/s?searchTerm=coffee+maker"}
GET /tabs/:tabId2/snapshot?userId=shopper
# Compare prices
# Twitter trending
POST /tabs/:tabId1/navigate
{"userId": "monitor", "macro": "@twitter_search", "query": "#AI"}
# Instagram hashtag
POST /tabs/:tabId2/navigate
{"userId": "monitor", "macro": "@instagram_search", "query": "AI"}
# TikTok search
POST /tabs/:tabId3/navigate
{"userId": "monitor", "macro": "@tiktok_search", "query": "AI tutorial"}
Adding custom macros
Custom macros require modifying lib/macros.js - there’s no runtime registration API.
To add a new macro:
- Edit
lib/macros.js:
const MACROS = {
// ... existing macros ...
'@custom_search': (query) => `https://example.com/search?q=${encodeURIComponent(query || '')}`,
};
- Restart server:
- Use new macro:
POST /tabs/:tabId/navigate
{"userId": "agent1", "macro": "@custom_search", "query": "test"}
Macro expansion cost
Macro expansion is synchronous and lightweight:
const targetUrl = expandMacro(macro, query); // ~0.1ms
No measurable performance impact compared to direct URL usage.
JSON responses are typically faster than HTML:
- Smaller payload (25 posts ≈ 50KB JSON vs 500KB+ HTML)
- No need to wait for page hydration
- Direct parsing without accessibility tree traversal
For Reddit data extraction, always use @reddit_search or @reddit_subreddit macros to get JSON directly.
Debugging
See expanded URL
Check server logs for expanded URL:
npm start
# In another terminal
POST /tabs/:tabId/navigate
{"userId": "test", "macro": "@google_search", "query": "test"}
# Server logs:
# {"level":"info","msg":"navigated","tabId":"...","url":"https://www.google.com/search?q=test"}
List all macros
From AGENTS.md:87-100:
| Macro | Site |
|-------|------|
| `@google_search` | Google |
| `@youtube_search` | YouTube |
...
Or programmatically:
const { getSupportedMacros } = require('./lib/macros');
console.log(getSupportedMacros());