Skip to content

Commit 42c33c6

Browse files
feat: Expose captcha task and challenge outcomes
Stainless-Generated-From: 14730d8ad0f9f106005c29e8088dfff1ccfce75a
1 parent 1c6986d commit 42c33c6

8 files changed

Lines changed: 186 additions & 8 deletions

api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ Types:
152152
from kernel.types.browsers import (
153153
BrowserAPICallEvent,
154154
BrowserCallStack,
155+
BrowserCaptchaChallengeResultEvent,
155156
BrowserCaptchaSolveResultEvent,
157+
BrowserCaptchaSolveStartedEvent,
156158
BrowserCdpCommandEvent,
157159
BrowserCdpCommandMethod,
158160
BrowserCdpConnectEvent,

src/kernel/types/browsers/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
from .browser_live_view_disconnect_event import BrowserLiveViewDisconnectEvent as BrowserLiveViewDisconnectEvent
8888
from .browser_monitor_disconnected_event import BrowserMonitorDisconnectedEvent as BrowserMonitorDisconnectedEvent
8989
from .computer_capture_screenshot_params import ComputerCaptureScreenshotParams as ComputerCaptureScreenshotParams
90+
from .browser_captcha_solve_started_event import BrowserCaptchaSolveStartedEvent as BrowserCaptchaSolveStartedEvent
9091
from .browser_telemetry_categories_config import BrowserTelemetryCategoriesConfig as BrowserTelemetryCategoriesConfig
9192
from .browser_network_loading_failed_event import BrowserNetworkLoadingFailedEvent as BrowserNetworkLoadingFailedEvent
9293
from .browser_telemetry_cdp_control_config import BrowserTelemetryCdpControlConfig as BrowserTelemetryCdpControlConfig
@@ -99,6 +100,9 @@
99100
from .computer_set_cursor_visibility_params import (
100101
ComputerSetCursorVisibilityParams as ComputerSetCursorVisibilityParams,
101102
)
103+
from .browser_captcha_challenge_result_event import (
104+
BrowserCaptchaChallengeResultEvent as BrowserCaptchaChallengeResultEvent,
105+
)
102106
from .browser_monitor_reconnect_failed_event import (
103107
BrowserMonitorReconnectFailedEvent as BrowserMonitorReconnectFailedEvent,
104108
)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
from typing import Optional
4+
from typing_extensions import Literal
5+
6+
from ..._models import BaseModel
7+
from .browser_event_source import BrowserEventSource
8+
9+
__all__ = ["BrowserCaptchaChallengeResultEvent", "Data"]
10+
11+
12+
class Data(BaseModel):
13+
"""Per-challenge payload.
14+
15+
This event is emitted once per challenge and determines its overall outcome; captcha_solve_started and captcha_solve_result describe individual tasks and may occur multiple times within the challenge.
16+
"""
17+
18+
captcha_type: Literal["hcaptcha", "recaptcha_v2", "recaptcha_v3", "turnstile", "geetest", "press_and_hold", "other"]
19+
"""Captcha kind.
20+
21+
Enterprise reCAPTCHA variants are grouped into their version bucket
22+
(recaptcha_v2 or recaptcha_v3), press-and-hold challenges use press_and_hold,
23+
and unlisted kinds use other.
24+
"""
25+
26+
challenge_id: str
27+
"""Opaque identifier shared by events for one visible challenge.
28+
29+
An image-grid captcha may create multiple task_id values for one challenge_id.
30+
The same value may continue across a page reload when the challenge episode
31+
continues. It does not indicate task ordering or challenge completion.
32+
"""
33+
34+
duration_ms: float
35+
"""
36+
Wall-clock duration from the challenge appearing to its terminal outcome,
37+
covering every solver attempt in between.
38+
"""
39+
40+
status: Literal["solved", "failure", "timeout", "abandoned"]
41+
"""Terminal outcome of the visible challenge.
42+
43+
solved: the page observed the challenge clear after a solver attempt. failure: a
44+
terminal solver failure occurred, or all attempts ended while the challenge
45+
remained. timeout: the challenge-level wait budget expired while the challenge
46+
remained. abandoned: observation ended without an attributable terminal
47+
challenge outcome. This includes a dismissed widget or page unload without a
48+
solved signal or terminal solver outcome, and a token appearing while multiple
49+
same-provider challenges are open, because the producer cannot attribute that
50+
token to this visible challenge. A captcha_solve_result with the same
51+
challenge_id may therefore report success while the challenge result reports
52+
abandoned. A solved challenge does not prove the site accepted the token or that
53+
the guarded action succeeded.
54+
"""
55+
56+
website_host: Optional[str] = None
57+
"""Host of the page where the challenge appeared."""
58+
59+
website_path: Optional[str] = None
60+
"""Path of the page where the challenge appeared. Query string excluded."""
61+
62+
63+
class BrowserCaptchaChallengeResultEvent(BaseModel):
64+
"""A visible captcha challenge reached a terminal outcome."""
65+
66+
category: Literal["captcha"]
67+
68+
data: Data
69+
"""Per-challenge payload.
70+
71+
This event is emitted once per challenge and determines its overall outcome;
72+
captcha_solve_started and captcha_solve_result describe individual tasks and may
73+
occur multiple times within the challenge.
74+
"""
75+
76+
source: BrowserEventSource
77+
"""Provenance metadata identifying which producer emitted the event."""
78+
79+
ts: int
80+
"""Event timestamp in Unix microseconds."""
81+
82+
type: Literal["captcha_challenge_result"]
83+
84+
truncated: Optional[bool] = None
85+
"""True if the data field was truncated due to size limits."""

src/kernel/types/browsers/browser_captcha_solve_result_event.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,20 @@
1010

1111

1212
class Data(BaseModel):
13-
captcha_type: Literal["hcaptcha", "recaptcha_v2", "recaptcha_v3", "turnstile", "geetest", "other"]
14-
"""Captcha vendor family.
13+
captcha_type: Literal["hcaptcha", "recaptcha_v2", "recaptcha_v3", "turnstile", "geetest", "press_and_hold", "other"]
14+
"""Captcha kind.
1515
16-
Provider-specific task names are normalized into this set; anything not covered
17-
is reported as other.
16+
Enterprise reCAPTCHA variants are grouped into their version bucket
17+
(recaptcha_v2 or recaptcha_v3), press-and-hold challenges use press_and_hold,
18+
and unlisted kinds use other.
1819
"""
1920

2021
duration_ms: float
21-
"""Wall-clock duration from solve start to terminal outcome."""
22+
"""Wall-clock duration from solve start to terminal outcome.
23+
24+
Authoritative solve timing; do not derive it from the gap to a
25+
captcha_solve_started event, whose delivery and ordering are not guaranteed.
26+
"""
2227

2328
status: Literal["success", "failure", "timeout", "abandoned"]
2429
"""Terminal outcome.
@@ -28,14 +33,22 @@ class Data(BaseModel):
2833
budget. abandoned: caller cancelled or the page navigated away mid-solve.
2934
"""
3035

36+
challenge_id: Optional[str] = None
37+
"""Opaque identifier shared by events for one visible challenge.
38+
39+
An image-grid captcha may create multiple task_id values for one challenge_id.
40+
The same value may continue across a page reload when the challenge episode
41+
continues. It does not indicate task ordering or challenge completion.
42+
"""
43+
3144
error_code: Optional[str] = None
3245
"""Solver-specific error code on failure (e.g.
3346
3447
ERROR_CAPTCHA_UNSOLVABLE). Absent on success.
3548
"""
3649

3750
task_id: Optional[str] = None
38-
"""Solver-assigned identifier. Opaque, useful for support cross-references."""
51+
"""Opaque identifier shared with the matching captcha_solve_started."""
3952

4053
website_host: Optional[str] = None
4154
"""Host of the page where the captcha was solved."""
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
from typing import Optional
4+
from typing_extensions import Literal
5+
6+
from ..._models import BaseModel
7+
from .browser_event_source import BrowserEventSource
8+
9+
__all__ = ["BrowserCaptchaSolveStartedEvent", "Data"]
10+
11+
12+
class Data(BaseModel):
13+
"""Per-task payload.
14+
15+
A visible challenge may create multiple tasks. When present, task_id correlates this event with a captcha_solve_result, while challenge_id groups tasks from the same challenge. Events may arrive out of order or be absent, so their arrival does not indicate current solve state.
16+
"""
17+
18+
captcha_type: Literal["hcaptcha", "recaptcha_v2", "recaptcha_v3", "turnstile", "geetest", "press_and_hold", "other"]
19+
"""Captcha kind.
20+
21+
Enterprise reCAPTCHA variants are grouped into their version bucket
22+
(recaptcha_v2 or recaptcha_v3), press-and-hold challenges use press_and_hold,
23+
and unlisted kinds use other.
24+
"""
25+
26+
challenge_id: Optional[str] = None
27+
"""Opaque identifier shared by events for one visible challenge.
28+
29+
An image-grid captcha may create multiple task_id values for one challenge_id.
30+
The same value may continue across a page reload when the challenge episode
31+
continues. It does not indicate task ordering or challenge completion.
32+
"""
33+
34+
task_id: Optional[str] = None
35+
"""Opaque identifier shared with the matching captcha_solve_result."""
36+
37+
website_host: Optional[str] = None
38+
"""Host of the page where the captcha is being solved.
39+
40+
May be empty for solver tasks that carry no page URL.
41+
"""
42+
43+
website_path: Optional[str] = None
44+
"""Path of the page where the captcha is being solved. Query string excluded."""
45+
46+
47+
class BrowserCaptchaSolveStartedEvent(BaseModel):
48+
"""A captcha solver accepted a task."""
49+
50+
category: Literal["captcha"]
51+
52+
data: Data
53+
"""Per-task payload.
54+
55+
A visible challenge may create multiple tasks. When present, task_id correlates
56+
this event with a captcha_solve_result, while challenge_id groups tasks from the
57+
same challenge. Events may arrive out of order or be absent, so their arrival
58+
does not indicate current solve state.
59+
"""
60+
61+
source: BrowserEventSource
62+
"""Provenance metadata identifying which producer emitted the event."""
63+
64+
ts: int
65+
"""Event timestamp in Unix microseconds."""
66+
67+
type: Literal["captcha_solve_started"]
68+
69+
truncated: Optional[bool] = None
70+
"""True if the data field was truncated due to size limits."""

src/kernel/types/browsers/browser_telemetry_categories_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class BrowserTelemetryCategoriesConfig(BaseModel):
1616
"""
1717

1818
captcha: Optional[BrowserTelemetryCategoryConfig] = None
19-
"""Captcha solve attempt outcomes. On by default."""
19+
"""Captcha solver tasks and visible challenge outcomes. On by default."""
2020

2121
connection: Optional[BrowserTelemetryCategoryConfig] = None
2222
"""Client attach/detach lifecycle for the CDP proxy and live view. On by default."""

src/kernel/types/browsers/browser_telemetry_categories_config_param.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class BrowserTelemetryCategoriesConfigParam(TypedDict, total=False):
1717
"""
1818

1919
captcha: BrowserTelemetryCategoryConfigParam
20-
"""Captcha solve attempt outcomes. On by default."""
20+
"""Captcha solver tasks and visible challenge outcomes. On by default."""
2121

2222
connection: BrowserTelemetryCategoryConfigParam
2323
"""Client attach/detach lifecycle for the CDP proxy and live view. On by default."""

src/kernel/types/browsers/browser_telemetry_event.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@
3535
from .browser_captcha_solve_result_event import BrowserCaptchaSolveResultEvent
3636
from .browser_live_view_disconnect_event import BrowserLiveViewDisconnectEvent
3737
from .browser_monitor_disconnected_event import BrowserMonitorDisconnectedEvent
38+
from .browser_captcha_solve_started_event import BrowserCaptchaSolveStartedEvent
3839
from .browser_network_loading_failed_event import BrowserNetworkLoadingFailedEvent
3940
from .browser_page_dom_content_loaded_event import BrowserPageDomContentLoadedEvent
4041
from .browser_page_navigation_settled_event import BrowserPageNavigationSettledEvent
42+
from .browser_captcha_challenge_result_event import BrowserCaptchaChallengeResultEvent
4143
from .browser_monitor_reconnect_failed_event import BrowserMonitorReconnectFailedEvent
4244
from .browser_interaction_scroll_settled_event import BrowserInteractionScrollSettledEvent
4345

@@ -76,7 +78,9 @@
7678
BrowserCdpDisconnectEvent,
7779
BrowserLiveViewConnectEvent,
7880
BrowserLiveViewDisconnectEvent,
81+
BrowserCaptchaSolveStartedEvent,
7982
BrowserCaptchaSolveResultEvent,
83+
BrowserCaptchaChallengeResultEvent,
8084
BrowserSystemOomKillEvent,
8185
BrowserServiceCrashedEvent,
8286
],

0 commit comments

Comments
 (0)