Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 45 additions & 45 deletions README.md

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions go/extend-browserbase/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Stagehand + Browserbase + Extend: Download Expense Receipts and Parse with Extend AI

Stagehand is the SDK for browser agents.

## AT A GLANCE

- **Goal**: Automate downloading receipts from an expense portal and extract structured receipt data using AI-powered document parsing.
- **Pattern Template**: Demonstrates the integration pattern of Browserbase (browser automation + download capture) + Extend AI (schema-based document extraction) in Go.
- **Workflow**: Stagehand navigates the expense portal and clicks each receipt's download link; Browserbase captures downloads. The program polls the Browserbase Downloads API for the session's files, saves them locally, then optionally sends them to Extend for structured extraction (vendor, date, totals, line items, etc.).
- **Download Handling**: Implements retry/polling around Browserbase's Downloads API until the expected files have synced.
- **Structured Extraction**: Extend AI extraction with a typed inline config built from the Extend Go SDK; results written to `output/results/receipts.json` and `receipts.csv`.
- Docs → [Browserbase Downloads](https://docs.browserbase.com/features/downloads) | [Extend AI](https://docs.extend.ai)

## GLOSSARY

- **Act**: perform UI actions from natural language prompts or observed actions (click, scroll, navigate)
Docs → https://docs.stagehand.dev/v4/basics/act
- **Observe**: find and return interactive elements on the page matching a description, without performing actions. Used here to locate all individual download buttons before clicking them.
Docs → https://docs.stagehand.dev/v4/basics/observe
- **Browserbase Downloads**: When files are downloaded during a browser session, Browserbase captures and stores them. Files are listed and retrieved individually via the Downloads REST API.
Docs → https://docs.browserbase.com/features/downloads
- **Extend AI extraction**: A configurable document extraction pipeline that parses files against a JSON schema and returns structured data. Config can be passed inline or via a saved extractor resource.
Docs → https://docs.extend.ai/extraction/overview
- **Download polling**: Browserbase syncs downloads in real time; the program retries every 2 seconds until the files are available or a timeout is reached.

## QUICKSTART

1. Install Go 1.26 or newer (`go version`).
2. `cd go/extend-browserbase`
3. Set the required API keys in your environment:
- `export BROWSERBASE_API_KEY=your_browserbase_api_key`
- `export EXTEND_API_KEY=your_extend_api_key` (optional — enables receipt parsing)
4. `go mod download`
5. `go run .`

## EXPECTED OUTPUT

- Launches a Browserbase browser and attaches Stagehand V4; Live View remains available in the Sessions dashboard
- Navigates to the expense portal and finds all per-receipt download links via Observe
- Clicks each download link; Browserbase captures files
- After closing the session, polls the Downloads API and saves each file to `output/documents/`
- If `EXTEND_API_KEY` is set: uploads each file to Extend and runs extraction with the inline config, writes `output/results/receipts.json` and `receipts.csv`
- Closes Stagehand and the browser cleanly

## COMMON PITFALLS

- Missing Go installation: ensure Go 1.26+ is installed
- Module not found: run `go mod download` if dependencies are not resolved
- Missing credentials: verify `BROWSERBASE_API_KEY` is set in your environment
- Download timeout: increase `downloadTimeout` if downloads take longer than 60 seconds
- No downloads found: ensure the download clicks actually triggered (inspect the session in the Browserbase dashboard)
- Rate limiting on Extend: the Extend SDK retries 429 and 5xx responses with exponential backoff (`option.WithMaxAttempts`), but very large batches may need `extractBatchSize` reduced from 9
- Find more information on your Browserbase dashboard → https://www.browserbase.com/sign-in

## USE CASES

• Expense automation: Download receipts from expense portals and extract vendor, date, totals, and line items for accounting systems.
• Document batch processing: Collect files from web portals and run structured extraction across all of them with a single program.
• Receipt digitization: Convert paper/PDF receipts into structured JSON and CSV for import into ERP, bookkeeping, or reimbursement tools.

## NEXT STEPS

• Parameterize the portal URL: Accept the expense portal URL from an env var or flag to support different receipt sources.
• Custom schemas: Modify `receiptExtractionConfig` to extract different document types (invoices, W-2s, contracts) by changing the JSON schema.
• Add validation: Compare extracted totals against line item sums to flag discrepancies or incomplete extractions.
• Production extraction: Swap the synchronous `client.Extract` call for `client.ExtractRuns.Create` with polling or webhooks for long-running documents.
• Scheduled runs: Deploy on cron/Lambda to periodically check for new receipts and process them automatically.

## HELPFUL RESOURCES

📚 Stagehand Docs: https://docs.stagehand.dev/v4/first-steps/introduction
📚 Browserbase Downloads: https://docs.browserbase.com/features/downloads
📚 Extend AI: https://docs.extend.ai
📚 Extend Go SDK: https://github.com/extend-hq/extend-go-sdk
🎮 Browserbase: https://www.browserbase.com
💡 Try it out: https://www.browserbase.com/playground
🔧 Templates: https://www.browserbase.com/templates
📧 Need help? support@browserbase.com
💬 Discord: http://stagehand.dev/discord
21 changes: 21 additions & 0 deletions go/extend-browserbase/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module extend-browserbase

go 1.26.0

require (
github.com/browserbase/stagehand/packages/sdk-go/v4 v4.0.2
github.com/extend-hq/extend-go-sdk v0.6.0
)

require (
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.2 // indirect
github.com/coder/websocket v1.8.13 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/invopop/jsonschema v0.14.0 // indirect
github.com/pb33f/ordered-map/v2 v2.3.1 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.yaml.in/yaml/v4 v4.0.0-rc.2 // indirect
golang.org/x/mod v0.38.0 // indirect
)
42 changes: 42 additions & 0 deletions go/extend-browserbase/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/browserbase/stagehand/packages/sdk-go/v4 v4.0.2 h1:axCIlzMz6Kao32Wli7C6uZVHbEc5MzmsUDAbf2y9TXw=
github.com/browserbase/stagehand/packages/sdk-go/v4 v4.0.2/go.mod h1:Z4qkSeN4whiyoYk+jqKbwYbUPu16JgmvEZWtiiaXyqY=
github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk=
github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/extend-hq/extend-go-sdk v0.6.0 h1:ZP0TLd77YtFyD8bMxYdpWIsymuJpYdpiFcH+QTtN6vQ=
github.com/extend-hq/extend-go-sdk v0.6.0/go.mod h1:OGwNG071bADLZ/BicWu/TLYn+QGELr/r051eECkfcn0=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/invopop/jsonschema v0.14.0 h1:MHQqLhvpNUZfw+hM3AZDYK7jxO8FZoQeQM77g8iyZjg=
github.com/invopop/jsonschema v0.14.0/go.mod h1:ygm6C2EaVNMBDPpaPlnOA2pFAxBnxGjFlMZABxm9n2I=
github.com/pb33f/ordered-map/v2 v2.3.1 h1:5319HDO0aw4DA4gzi+zv4FXU9UlSs3xGZ40wcP1nBjY=
github.com/pb33f/ordered-map/v2 v2.3.1/go.mod h1:qxFQgd0PkVUtOMCkTapqotNgzRhMPL7VvaHKbd1HnmQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.yaml.in/yaml/v4 v4.0.0-rc.2 h1:/FrI8D64VSr4HtGIlUtlFMGsm7H7pWTbj6vOLVZcA6s=
go.yaml.in/yaml/v4 v4.0.0-rc.2/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk=
golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading