Skip to content
Merged
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
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ capture metadata https://example.com --pretty
capture animated https://example.com -X duration=5 -o recording.gif

capture sessions create --max-ttl-seconds 300 --pretty
capture sessions create --cdp --pretty
capture sessions get sess_123 --pretty
capture sessions action sess_123 goto --payload-json '{"url":"https://example.com"}'
capture sessions action sess_123 screenshot -X fullPage=true --pretty
Expand Down Expand Up @@ -108,9 +109,21 @@ func main() {
"fullPage": true,
})
c.CloseSession(sessionID)

// CDP browser sessions
cdpCreated, _ := c.CreateSession(&capture.CreateSessionOptions{
CDP: true,
})
cdpSession := cdpCreated["session"].(map[string]interface{})
connectURL := cdpSession["connectUrl"].(string)
println(connectURL)
}
```

CDP sessions return a `connectUrl` in the session object for Chrome DevTools
Protocol clients. CDP cannot be combined with `Proxy`/`--proxy` or
`BypassBotDetection`/`--bypass-bot-detection`.

### Options

```go
Expand Down
1 change: 1 addition & 0 deletions capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type RequestOptions map[string]interface{}

type CreateSessionOptions struct {
MaxTtlSeconds int `json:"maxTtlSeconds,omitempty"`
CDP bool `json:"cdp,omitempty"`
Proxy bool `json:"proxy,omitempty"`
BypassBotDetection bool `json:"bypassBotDetection,omitempty"`
}
Expand Down
41 changes: 41 additions & 0 deletions capture_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,12 +359,53 @@ func TestCreateSession(t *testing.T) {
if requestBody["maxTtlSeconds"] != float64(300) || requestBody["proxy"] != true {
t.Fatalf("unexpected request body: %#v", requestBody)
}
if _, ok := requestBody["cdp"]; ok {
t.Fatalf("cdp should be omitted for non-CDP session requests: %#v", requestBody)
}
session, ok := response["session"].(map[string]interface{})
if !ok || response["success"] != true || session["id"] != "sess_123" || session["maxTtlSeconds"] != float64(300) {
t.Fatalf("unexpected response: %#v", response)
}
}

func TestCreateSessionCDP(t *testing.T) {
var requestBody map[string]interface{}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
t.Errorf("failed to decode request body: %v", err)
}
w.WriteHeader(http.StatusCreated)
_ = json.NewEncoder(w).Encode(map[string]interface{}{
"success": true,
"session": map[string]interface{}{
"id": "sess_cdp",
"status": "active",
"cdp": true,
"connectUrl": "wss://connect.capture.page/sess_cdp",
},
})
}))
defer server.Close()

c := New("user_123", "secret")
c.EdgeURL = server.URL
response, err := c.CreateSession(&CreateSessionOptions{CDP: true})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

if requestBody["cdp"] != true {
t.Fatalf("expected cdp request body, got %#v", requestBody)
}
if _, ok := requestBody["proxy"]; ok {
t.Fatalf("proxy should be omitted for CDP-only session requests: %#v", requestBody)
}
session, ok := response["session"].(map[string]interface{})
if !ok || session["cdp"] != true || session["connectUrl"] != "wss://connect.capture.page/sess_cdp" {
t.Fatalf("unexpected response: %#v", response)
}
}

func TestGetCloseAndExecuteAction(t *testing.T) {
var requests []string
var actionBody map[string]interface{}
Expand Down
12 changes: 12 additions & 0 deletions example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,16 @@ func main() {
fmt.Println("PDF saved as document.pdf")
}
}

// Example 7: Create a CDP session and read its connectUrl
cdpSessionResp, err := c.CreateSession(&capture.CreateSessionOptions{
CDP: true,
})
if err != nil {
log.Printf("Error creating CDP session: %v", err)
} else if session, ok := cdpSessionResp["session"].(map[string]interface{}); ok {
if connectURL, ok := session["connectUrl"].(string); ok {
fmt.Printf("CDP Connect URL: %s\n", connectURL)
}
}
}
3 changes: 3 additions & 0 deletions internal/cli/sessions.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ var sessionsActionCmd = &cobra.Command{

var (
sessionMaxTTLSeconds int
sessionCDP bool
sessionProxy bool
sessionBypassBotDetection bool
sessionsPretty bool
Expand All @@ -58,6 +59,7 @@ func init() {
sessionsCmd.AddCommand(sessionsCreateCmd, sessionsGetCmd, sessionsCloseCmd, sessionsActionCmd)

sessionsCreateCmd.Flags().IntVar(&sessionMaxTTLSeconds, "max-ttl-seconds", 0, "Maximum session lifetime in seconds")
sessionsCreateCmd.Flags().BoolVar(&sessionCDP, "cdp", false, "Create a Chrome DevTools Protocol session")
sessionsCreateCmd.Flags().BoolVar(&sessionProxy, "proxy", false, "Use the authenticated user's configured browser proxy")
sessionsCreateCmd.Flags().BoolVar(&sessionBypassBotDetection, "bypass-bot-detection", false, "Use Capture's bot-detection bypass browser when available")
sessionsCreateCmd.Flags().BoolVar(&sessionsPretty, "pretty", false, "Pretty print JSON output")
Expand All @@ -74,6 +76,7 @@ func runSessionsCreate(cmd *cobra.Command, args []string) error {
client := newCaptureClient()
options := &capture.CreateSessionOptions{
MaxTtlSeconds: sessionMaxTTLSeconds,
CDP: sessionCDP,
Proxy: sessionProxy,
BypassBotDetection: sessionBypassBotDetection,
}
Expand Down
13 changes: 13 additions & 0 deletions internal/cli/sessions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cli

import "testing"

func TestSessionsCreateCommandHasCDPFlag(t *testing.T) {
flag := sessionsCreateCmd.Flags().Lookup("cdp")
if flag == nil {
t.Fatal("expected sessions create --cdp flag")
}
if flag.DefValue != "false" {
t.Fatalf("expected --cdp default false, got %q", flag.DefValue)
}
}
Loading