@biggora/claude-plugins 1.1.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/README.md +24 -17
  3. package/package.json +1 -1
  4. package/registry/registry.json +319 -244
  5. package/specs/coding.md +24 -0
  6. package/specs/pod.md +2 -0
  7. package/src/skills/captcha/README.md +221 -0
  8. package/src/skills/captcha/SKILL.md +355 -0
  9. package/src/skills/captcha/references/captcha-types.md +254 -0
  10. package/src/skills/captcha/references/services.md +172 -0
  11. package/src/skills/captcha/references/stealth.md +238 -0
  12. package/src/skills/captcha/scripts/solve_captcha.py +323 -0
  13. package/src/skills/captcha/scripts/solve_image_grid.py +350 -0
  14. package/src/skills/codex-cli/SKILL.md +21 -11
  15. package/src/skills/gemini-cli/SKILL.md +27 -13
  16. package/src/skills/gemini-cli/references/commands.md +21 -14
  17. package/src/skills/gemini-cli/references/configuration.md +23 -18
  18. package/src/skills/gemini-cli/references/headless-and-scripting.md +7 -17
  19. package/src/skills/gemini-cli/references/mcp-and-extensions.md +12 -6
  20. package/src/skills/google-merchant-api/SKILL.md +581 -0
  21. package/src/skills/google-merchant-api/references/accounts.md +247 -0
  22. package/src/skills/google-merchant-api/references/content-api-legacy.md +216 -0
  23. package/src/skills/google-merchant-api/references/datasources.md +233 -0
  24. package/src/skills/google-merchant-api/references/inventories.md +201 -0
  25. package/src/skills/google-merchant-api/references/migration.md +267 -0
  26. package/src/skills/google-merchant-api/references/products.md +316 -0
  27. package/src/skills/google-merchant-api/references/promotions.md +201 -0
  28. package/src/skills/google-merchant-api/references/reports.md +240 -0
  29. package/src/skills/lv-aggregators-api/SKILL.md +113 -0
  30. package/src/skills/lv-aggregators-api/references/integration-guide.md +368 -0
  31. package/src/skills/lv-aggregators-api/references/kurpirkt.md +103 -0
  32. package/src/skills/lv-aggregators-api/references/salidzini.md +122 -0
  33. package/src/skills/notebook-lm/SKILL.md +1 -1
  34. package/src/skills/screen-recording/SKILL.md +243 -213
  35. package/src/skills/screen-recording/references/design-patterns.md +4 -2
  36. package/src/skills/screen-recording/references/ffmpeg-recording.md +473 -0
  37. package/src/skills/screen-recording/references/{approach1-programmatic.md → programmatic-generation.md} +45 -22
  38. package/src/skills/screen-recording/references/python-fallback.md +222 -0
  39. package/src/skills/tailwindcss-best-practices/SKILL.md +180 -0
  40. package/src/skills/tailwindcss-best-practices/references/best-practices-utility-patterns.md +87 -0
  41. package/src/skills/tailwindcss-best-practices/references/core-installation.md +109 -0
  42. package/src/skills/tailwindcss-best-practices/references/core-preflight.md +200 -0
  43. package/src/skills/tailwindcss-best-practices/references/core-responsive.md +163 -0
  44. package/src/skills/tailwindcss-best-practices/references/core-source-detection.md +114 -0
  45. package/src/skills/tailwindcss-best-practices/references/core-theme.md +108 -0
  46. package/src/skills/tailwindcss-best-practices/references/core-utility-classes.md +59 -0
  47. package/src/skills/tailwindcss-best-practices/references/core-variants.md +204 -0
  48. package/src/skills/tailwindcss-best-practices/references/effects-form-controls.md +76 -0
  49. package/src/skills/tailwindcss-best-practices/references/effects-mask.md +91 -0
  50. package/src/skills/tailwindcss-best-practices/references/effects-scroll-snap.md +59 -0
  51. package/src/skills/tailwindcss-best-practices/references/effects-text-shadow.md +78 -0
  52. package/src/skills/tailwindcss-best-practices/references/effects-transition-animation.md +80 -0
  53. package/src/skills/tailwindcss-best-practices/references/effects-visibility-interactivity.md +82 -0
  54. package/src/skills/tailwindcss-best-practices/references/features-content-detection.md +175 -0
  55. package/src/skills/tailwindcss-best-practices/references/features-custom-styles.md +203 -0
  56. package/src/skills/tailwindcss-best-practices/references/features-dark-mode.md +137 -0
  57. package/src/skills/tailwindcss-best-practices/references/features-functions-directives.md +241 -0
  58. package/src/skills/tailwindcss-best-practices/references/features-upgrade.md +160 -0
  59. package/src/skills/tailwindcss-best-practices/references/layout-aspect-ratio.md +39 -0
  60. package/src/skills/tailwindcss-best-practices/references/layout-columns.md +80 -0
  61. package/src/skills/tailwindcss-best-practices/references/layout-display.md +110 -0
  62. package/src/skills/tailwindcss-best-practices/references/layout-flexbox.md +112 -0
  63. package/src/skills/tailwindcss-best-practices/references/layout-grid.md +87 -0
  64. package/src/skills/tailwindcss-best-practices/references/layout-height.md +97 -0
  65. package/src/skills/tailwindcss-best-practices/references/layout-inset.md +103 -0
  66. package/src/skills/tailwindcss-best-practices/references/layout-logical-properties.md +92 -0
  67. package/src/skills/tailwindcss-best-practices/references/layout-margin.md +126 -0
  68. package/src/skills/tailwindcss-best-practices/references/layout-min-max-sizing.md +63 -0
  69. package/src/skills/tailwindcss-best-practices/references/layout-object-fit-position.md +64 -0
  70. package/src/skills/tailwindcss-best-practices/references/layout-overflow.md +57 -0
  71. package/src/skills/tailwindcss-best-practices/references/layout-padding.md +77 -0
  72. package/src/skills/tailwindcss-best-practices/references/layout-position.md +85 -0
  73. package/src/skills/tailwindcss-best-practices/references/layout-tables.md +67 -0
  74. package/src/skills/tailwindcss-best-practices/references/layout-width.md +102 -0
  75. package/src/skills/tailwindcss-best-practices/references/transform-base.md +68 -0
  76. package/src/skills/tailwindcss-best-practices/references/transform-rotate.md +70 -0
  77. package/src/skills/tailwindcss-best-practices/references/transform-scale.md +83 -0
  78. package/src/skills/tailwindcss-best-practices/references/transform-skew.md +62 -0
  79. package/src/skills/tailwindcss-best-practices/references/transform-translate.md +77 -0
  80. package/src/skills/tailwindcss-best-practices/references/typography-font-text.md +142 -0
  81. package/src/skills/tailwindcss-best-practices/references/typography-list-style.md +65 -0
  82. package/src/skills/tailwindcss-best-practices/references/typography-text-align.md +60 -0
  83. package/src/skills/tailwindcss-best-practices/references/visual-background.md +76 -0
  84. package/src/skills/tailwindcss-best-practices/references/visual-border.md +108 -0
  85. package/src/skills/tailwindcss-best-practices/references/visual-effects.md +111 -0
  86. package/src/skills/tailwindcss-best-practices/references/visual-svg.md +82 -0
  87. package/src/skills/test-mobile-app/SKILL.md +11 -6
  88. package/src/skills/test-mobile-app/scripts/analyze_apk.py +15 -4
  89. package/src/skills/test-mobile-app/scripts/check_environment.py +5 -5
  90. package/src/skills/test-mobile-app/scripts/run_tests.py +1 -1
  91. package/src/skills/test-web-ui/SKILL.md +264 -84
  92. package/src/skills/test-web-ui/scripts/discover.py +25 -12
  93. package/src/skills/test-web-ui/scripts/run_tests.py +3 -2
  94. package/src/skills/tm-search/SKILL.md +242 -106
  95. package/src/skills/tm-search/references/scraping-fallback.md +60 -95
  96. package/src/skills/tm-search/scripts/tm_search.py +453 -375
  97. package/src/skills/vite-best-practices/SKILL.md +115 -0
  98. package/src/skills/vite-best-practices/references/build-and-ssr.md +255 -0
  99. package/src/skills/vite-best-practices/references/core-config.md +231 -0
  100. package/src/skills/vite-best-practices/references/core-features.md +222 -0
  101. package/src/skills/vite-best-practices/references/core-plugin-api.md +294 -0
  102. package/src/skills/vite-best-practices/references/environment-api.md +108 -0
  103. package/src/skills/vite-best-practices/references/rolldown-migration.md +242 -0
  104. package/src/skills/screen-recording/references/approach2-xvfb.md +0 -232
@@ -0,0 +1,254 @@
1
+ # CAPTCHA Types — Detection & Injection Patterns
2
+
3
+ Reference for identifying which CAPTCHA is on a page and injecting the solved token.
4
+
5
+ ---
6
+
7
+ ## reCAPTCHA v2 (Checkbox)
8
+
9
+ The most common CAPTCHA. Shows a checkbox; sometimes shows an image grid challenge.
10
+
11
+ ### Detection
12
+ ```javascript
13
+ // Returns sitekey if reCAPTCHA v2 is present, null otherwise
14
+ const el = document.querySelector('.g-recaptcha, [data-sitekey]:not(.h-captcha):not(.cf-turnstile)');
15
+ el?.dataset?.sitekey ?? null;
16
+
17
+ // Alternative: extract from iframe src
18
+ const frame = document.querySelector('iframe[src*="recaptcha"]');
19
+ frame?.src?.match(/[?&]k=([^&]+)/)?.[1] ?? null;
20
+ ```
21
+
22
+ ### Parameters to collect
23
+ - `sitekey` — the `data-sitekey` attribute on `.g-recaptcha`
24
+ - `pageurl` — `window.location.href`
25
+
26
+ ### Token injection
27
+ ```javascript
28
+ function injectRecaptchaV2(token) {
29
+ // Set the hidden response field (may be display:none — that's fine)
30
+ document.querySelectorAll('[name="g-recaptcha-response"]').forEach(el => {
31
+ el.value = token;
32
+ });
33
+
34
+ // Trigger the registered callback
35
+ if (window.___grecaptcha_cfg) {
36
+ Object.values(window.___grecaptcha_cfg.clients || {}).forEach(client => {
37
+ Object.keys(client).forEach(key => {
38
+ const widget = client[key];
39
+ if (widget && typeof widget.callback === 'function') {
40
+ widget.callback(token);
41
+ }
42
+ });
43
+ });
44
+ }
45
+
46
+ // Fallback: look for a global callback name in the render call
47
+ // Search page source for: grecaptcha.render(..., { callback: 'FUNCTION_NAME' })
48
+ }
49
+ ```
50
+
51
+ ### Notes
52
+ - If injection has no effect, check if there's a `grecaptcha.render(element, { callback: fn })` call
53
+ in the page source — call that function with the token directly.
54
+ - Some sites wrap the callback in `window.onRecaptchaSuccess` or similar. Search the page for
55
+ `grecaptcha` to find where the callback is registered.
56
+
57
+ ---
58
+
59
+ ## reCAPTCHA v2 Invisible
60
+
61
+ No visible checkbox. Triggered programmatically with `grecaptcha.execute()`. Produces the same
62
+ token format as v2 checkbox.
63
+
64
+ ### Detection
65
+ ```javascript
66
+ // Invisible reCAPTCHA has no visible .g-recaptcha widget
67
+ // Look for grecaptcha.execute() calls or a render with { size: 'invisible' }
68
+ const src = document.documentElement.innerHTML;
69
+ const isInvisible = src.includes("size: 'invisible'") || src.includes('"invisible"');
70
+ ```
71
+
72
+ ### Solve with `--invisible` flag
73
+ ```bash
74
+ python scripts/solve_captcha.py --type recaptcha-v2 --invisible --sitekey KEY --pageurl URL
75
+ ```
76
+
77
+ ### Token injection
78
+ Same as v2 checkbox injection above.
79
+
80
+ ---
81
+
82
+ ## reCAPTCHA v3
83
+
84
+ Score-based, invisible. No user interaction at all. The site calls
85
+ `grecaptcha.execute(sitekey, {action: 'actionName'})` in its JS, then validates the returned
86
+ score server-side (scores range 0.0–1.0; bots score low).
87
+
88
+ ### Detection
89
+ ```javascript
90
+ // Look for grecaptcha.execute with a sitekey in the page source
91
+ // There is no visible widget — detection is by source inspection
92
+ const src = document.documentElement.innerHTML;
93
+ const match = src.match(/grecaptcha\.execute\(['"]([^'"]+)['"]/);
94
+ match?.[1] ?? null; // sitekey if found
95
+ ```
96
+
97
+ Or grep the page HTML for `grecaptcha.execute(` to find the sitekey and action name.
98
+
99
+ ### Parameters
100
+ - `sitekey` — from the `grecaptcha.execute('SITEKEY', ...)` call
101
+ - `pageurl` — `window.location.href`
102
+ - `action` — the action string in `{action: 'NAME'}`, e.g. `verify`, `submit`, `login`
103
+ - `min_score` — request a score of at least this value (default 0.5; lower = easier to solve)
104
+
105
+ ### Solve
106
+ ```bash
107
+ python scripts/solve_captcha.py --type recaptcha-v3 \
108
+ --sitekey SITEKEY --pageurl URL \
109
+ --action submit --min-score 0.7
110
+ ```
111
+
112
+ ### Token injection
113
+ v3 tokens are typically consumed by an AJAX call, not a visible form field. The site expects
114
+ the token in a specific request parameter. Two approaches:
115
+
116
+ 1. **Intercept the form submit** — inject the token before the AJAX fires:
117
+ ```javascript
118
+ // Override grecaptcha.execute to return your solved token
119
+ window.grecaptcha.execute = () => Promise.resolve(TOKEN);
120
+ ```
121
+
122
+ 2. **Set the hidden field** if the site stores the token in an input before submitting:
123
+ ```javascript
124
+ document.querySelectorAll('[name="g-recaptcha-response"], [name="token"]').forEach(el => {
125
+ el.value = TOKEN;
126
+ });
127
+ ```
128
+
129
+ ---
130
+
131
+ ## hCaptcha
132
+
133
+ Common on Cloudflare-protected and privacy-focused sites.
134
+
135
+ ### Detection
136
+ ```javascript
137
+ const el = document.querySelector('.h-captcha, [data-hcaptcha-sitekey]');
138
+ el?.dataset?.sitekey ?? document.querySelector('[data-sitekey].h-captcha')?.dataset?.sitekey ?? null;
139
+ ```
140
+
141
+ ### Solve
142
+ ```bash
143
+ python scripts/solve_captcha.py --type hcaptcha --sitekey KEY --pageurl URL
144
+ ```
145
+
146
+ ### Token injection
147
+ ```javascript
148
+ function injectHcaptcha(token) {
149
+ // Set the response field
150
+ document.querySelectorAll('[name="h-captcha-response"]').forEach(el => {
151
+ el.value = token;
152
+ });
153
+
154
+ // Trigger hCaptcha callback
155
+ if (window.hcaptcha) {
156
+ // Some sites register a callback via hcaptcha.render
157
+ const iframes = document.querySelectorAll('iframe[src*="hcaptcha"]');
158
+ // Try the global callback if defined
159
+ if (typeof window.onHcaptchaSuccess === 'function') window.onHcaptchaSuccess(token);
160
+ }
161
+ }
162
+ ```
163
+
164
+ If the above doesn't trigger the form to proceed, look for `data-callback` on the `.h-captcha`
165
+ element and call that function by name:
166
+ ```javascript
167
+ const callbackName = document.querySelector('[data-callback]')?.dataset?.callback;
168
+ if (callbackName && window[callbackName]) window[callbackName](token);
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Cloudflare Turnstile
174
+
175
+ Cloudflare's newer CAPTCHA, launched 2022. Invisible by default.
176
+
177
+ ### Detection
178
+ ```javascript
179
+ const el = document.querySelector('.cf-turnstile');
180
+ el?.dataset?.sitekey ?? null;
181
+ ```
182
+
183
+ ### Solve
184
+ ```bash
185
+ python scripts/solve_captcha.py --type turnstile --sitekey KEY --pageurl URL
186
+ ```
187
+
188
+ ### Token injection
189
+ ```javascript
190
+ function injectTurnstile(token) {
191
+ document.querySelectorAll('[name="cf-turnstile-response"]').forEach(el => {
192
+ el.value = token;
193
+ });
194
+
195
+ // Some sites use a callback
196
+ const callbackName = document.querySelector('.cf-turnstile')?.dataset?.callback;
197
+ if (callbackName && window[callbackName]) window[callbackName](token);
198
+ }
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Image / Text CAPTCHA
204
+
205
+ Classic distorted text or simple math CAPTCHAs. Send the image, get text back.
206
+
207
+ ### Detection
208
+ ```javascript
209
+ // Look for an image element with "captcha" in its src or alt
210
+ document.querySelector('img[src*="captcha" i], img[alt*="captcha" i]')?.src ?? null;
211
+ ```
212
+
213
+ ### Capture the image
214
+ ```python
215
+ # With Playwright: screenshot just the CAPTCHA element
216
+ captcha_el = page.query_selector('img[alt*="captcha" i]')
217
+ captcha_el.screenshot(path="captcha.png")
218
+ ```
219
+
220
+ Or fetch the image URL directly:
221
+ ```python
222
+ import urllib.request
223
+ img_url = page.evaluate("document.querySelector('img[src*=\"captcha\"]').src")
224
+ urllib.request.urlretrieve(img_url, "captcha.png")
225
+ ```
226
+
227
+ ### Solve
228
+ ```bash
229
+ python scripts/solve_captcha.py --type image --image captcha.png
230
+ ```
231
+
232
+ ### Use the result
233
+ ```javascript
234
+ // The solved token is the text answer, not a long JWT
235
+ document.querySelector('input[name*="captcha" i]').value = SOLVED_TEXT;
236
+ ```
237
+
238
+ ### Tips for better accuracy
239
+ - Crop to just the CAPTCHA image (no padding or surrounding UI)
240
+ - Convert to grayscale and increase contrast before sending
241
+ - If the CAPTCHA is math (e.g. "3 + 4 = ?"), the solver returns "7" as text
242
+
243
+ ---
244
+
245
+ ## Quick Reference Table
246
+
247
+ | Type | Detect selector | Key field to inject | Callback trigger |
248
+ |------|----------------|---------------------|-----------------|
249
+ | reCAPTCHA v2 | `.g-recaptcha` | `[name="g-recaptcha-response"]` | `___grecaptcha_cfg.clients[n][k].callback(token)` |
250
+ | reCAPTCHA v2 invisible | script source | `[name="g-recaptcha-response"]` | same as v2 |
251
+ | reCAPTCHA v3 | script source | hidden input or AJAX param | override `grecaptcha.execute` |
252
+ | hCaptcha | `.h-captcha` | `[name="h-captcha-response"]` | `[data-callback]` function |
253
+ | Turnstile | `.cf-turnstile` | `[name="cf-turnstile-response"]` | `[data-callback]` function |
254
+ | Image | `img[src*=captcha]` | text input near image | n/a |
@@ -0,0 +1,172 @@
1
+ # CAPTCHA Solving Services
2
+
3
+ Comparison of the three major services supported by `solve_captcha.py`.
4
+
5
+ All three use the same API endpoint format (2captcha-compatible), so you can switch
6
+ between them with only the `--service` flag.
7
+
8
+ ---
9
+
10
+ ## 2captcha
11
+
12
+ **Website:** https://2captcha.com
13
+ **`--service` flag:** `2captcha` (default)
14
+
15
+ The most widely documented and supported service. Operates since 2009.
16
+ Uses a combination of human workers and AI for solving.
17
+
18
+ ### Pricing (approximate)
19
+ | Type | Per 1,000 |
20
+ |------|-----------|
21
+ | reCAPTCHA v2 | $1.00–$1.50 |
22
+ | reCAPTCHA v3 | $2.00–$3.00 |
23
+ | hCaptcha | $1.50–$2.00 |
24
+ | Turnstile | $1.00–$1.50 |
25
+ | Image/text | $0.50–$1.00 |
26
+
27
+ ### Getting started
28
+ 1. Sign up at https://2captcha.com/register
29
+ 2. Add funds (minimum ~$3, accepts cards and crypto)
30
+ 3. Copy your API key from https://2captcha.com/enterpage
31
+
32
+ ### Free testing
33
+ 2captcha offers a demo mode at https://2captcha.com/demo/ — you can test all CAPTCHA
34
+ types without spending credits. The demo page at https://2captcha.com/demo/recaptcha-v2
35
+ is useful for verifying your integration works.
36
+
37
+ ### Checking balance
38
+ ```bash
39
+ curl "https://2captcha.com/res.php?key=YOUR_KEY&action=getbalance"
40
+ # → 4.25 (balance in USD)
41
+ ```
42
+
43
+ ### Average solve times
44
+ - reCAPTCHA v2: 20–35s
45
+ - reCAPTCHA v3: 30–60s
46
+ - hCaptcha: 20–40s
47
+ - Image: 5–15s
48
+
49
+ ---
50
+
51
+ ## CapMonster Cloud
52
+
53
+ **Website:** https://capmonster.cloud
54
+ **`--service` flag:** `capmonster`
55
+
56
+ AI-powered service (no human workers). Faster and cheaper than 2captcha for most types.
57
+ Uses machine learning models that have been trained on CAPTCHA datasets.
58
+
59
+ ### Pricing (approximate)
60
+ | Type | Per 1,000 |
61
+ |------|-----------|
62
+ | reCAPTCHA v2 | $0.60 |
63
+ | reCAPTCHA v3 | $1.50 |
64
+ | hCaptcha | $0.80 |
65
+ | Turnstile | $0.60 |
66
+ | Image/text | $0.30 |
67
+
68
+ ### Getting started
69
+ 1. Sign up at https://capmonster.cloud
70
+ 2. Add funds (minimum $2)
71
+ 3. Copy API key from dashboard
72
+
73
+ ### API compatibility note
74
+ CapMonster uses the same `/in.php` and `/res.php` endpoint format as 2captcha.
75
+ The `solve_captcha.py` script handles the URL switching automatically via `--service capmonster`.
76
+
77
+ ### Average solve times
78
+ - reCAPTCHA v2: 10–25s
79
+ - hCaptcha: 15–30s
80
+ - Image: 2–8s
81
+
82
+ ---
83
+
84
+ ## Anti-Captcha
85
+
86
+ **Website:** https://anti-captcha.com
87
+ **`--service` flag:** `anticaptcha`
88
+
89
+ One of the original CAPTCHA solving services. Good uptime and reliable for bulk tasks.
90
+
91
+ ### Pricing (approximate)
92
+ | Type | Per 1,000 |
93
+ |------|-----------|
94
+ | reCAPTCHA v2 | $0.70 |
95
+ | reCAPTCHA v3 | $1.80 |
96
+ | hCaptcha | $1.00 |
97
+ | Image/text | $0.70 |
98
+
99
+ ### Getting started
100
+ 1. Sign up at https://anti-captcha.com
101
+ 2. Add funds
102
+ 3. Copy API key from Account Settings
103
+
104
+ ---
105
+
106
+ ## Choosing a Service
107
+
108
+ | If you need... | Use |
109
+ |---------------|-----|
110
+ | Best documentation & community | 2captcha |
111
+ | Lowest cost + fastest for reCAPTCHA v2 | CapMonster |
112
+ | Bulk image CAPTCHA at low cost | CapMonster or Anti-Captcha |
113
+ | reCAPTCHA v3 reliability | 2captcha (more worker capacity) |
114
+ | Free credits to test | 2captcha ($1 signup bonus occasionally) |
115
+
116
+ ---
117
+
118
+ ## Using Multiple Services (Fallback)
119
+
120
+ If one service is down or out of credits, fall back to another:
121
+
122
+ ```python
123
+ import json, subprocess, os
124
+
125
+ def solve_with_fallback(captcha_type, sitekey, pageurl):
126
+ services = ["2captcha", "capmonster", "anticaptcha"]
127
+ for service in services:
128
+ key_env = f"CAPTCHA_API_KEY_{service.upper().replace('-', '_')}"
129
+ api_key = os.environ.get(key_env) or os.environ.get("CAPTCHA_API_KEY")
130
+ if not api_key:
131
+ continue
132
+ result = subprocess.run(
133
+ ["python", "scripts/solve_captcha.py",
134
+ "--type", captcha_type, "--sitekey", sitekey, "--pageurl", pageurl,
135
+ "--service", service, "--api-key", api_key],
136
+ capture_output=True, text=True
137
+ )
138
+ data = json.loads(result.stdout)
139
+ if data.get("success"):
140
+ return data["token"]
141
+ print(f"[captcha] {service} failed: {data.get('error')} — trying next service")
142
+ raise RuntimeError("All CAPTCHA solving services failed")
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Checking Your Balance
148
+
149
+ ```bash
150
+ # 2captcha
151
+ curl "https://2captcha.com/res.php?key=YOUR_KEY&action=getbalance"
152
+
153
+ # CapMonster
154
+ curl "https://api.capmonster.cloud/res.php?key=YOUR_KEY&action=getbalance"
155
+
156
+ # Anti-Captcha
157
+ curl "https://api.anti-captcha.com/res.php?key=YOUR_KEY&action=getbalance"
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Error Codes
163
+
164
+ | Code | Meaning | Fix |
165
+ |------|---------|-----|
166
+ | `ERROR_ZERO_BALANCE` | Account has no credits | Add funds at service dashboard |
167
+ | `ERROR_NO_SLOT_AVAILABLE` | Service overloaded | Retry in a few minutes |
168
+ | `ERROR_WRONG_CAPTCHA_ID` | Invalid task ID | Bug in code — report |
169
+ | `ERROR_CAPTCHA_UNSOLVABLE` | Solver gave up | Retry; if recurring, try another service |
170
+ | `ERROR_WRONG_USER_KEY` | Bad API key | Check key, no trailing spaces |
171
+ | `CAPCHA_NOT_READY` | Still processing | Normal — keep polling |
172
+ | `ERROR_IP_BANNED` | Your IP is blocked | Contact service support |
@@ -0,0 +1,238 @@
1
+ # Avoiding Bot Detection After Passing CAPTCHA
2
+
3
+ Passing the CAPTCHA itself is often not enough — the site may still flag and block your
4
+ session based on browser fingerprinting or behavioral signals. This document covers the
5
+ most common detection vectors and how to mitigate them.
6
+
7
+ ---
8
+
9
+ ## Why Sites Still Block After CAPTCHA
10
+
11
+ Modern anti-bot systems (Cloudflare, PerimeterX, DataDome, Kasada) score requests on
12
+ multiple signals **beyond** the CAPTCHA solution:
13
+
14
+ 1. **Browser fingerprint** — headless Chrome has telltale JS properties
15
+ 2. **Mouse / interaction patterns** — no mouse movement, instant form fills
16
+ 3. **Request headers** — missing or inconsistent Accept-Language, Referer, etc.
17
+ 4. **IP reputation** — data center IPs are pre-flagged
18
+ 5. **Cookie / session age** — fresh sessions with no history look suspicious
19
+ 6. **Timing** — solving a CAPTCHA in 15s (via API) and submitting instantly
20
+
21
+ ---
22
+
23
+ ## Playwright Stealth Mode
24
+
25
+ The single most impactful change: install and use `playwright-stealth` to patch the
26
+ headless detection markers.
27
+
28
+ ```bash
29
+ pip install playwright-stealth
30
+ ```
31
+
32
+ ```python
33
+ from playwright.sync_api import sync_playwright
34
+ from playwright_stealth import stealth_sync
35
+
36
+ with sync_playwright() as p:
37
+ browser = p.chromium.launch(headless=True)
38
+ page = browser.new_page()
39
+ stealth_sync(page) # patches ~30 fingerprinting vectors
40
+ page.goto("https://example.com")
41
+ ```
42
+
43
+ ### What stealth patches
44
+ - `navigator.webdriver` — set to `undefined` instead of `true`
45
+ - Chrome runtime properties — adds `chrome.runtime` and related objects
46
+ - Plugin / mimeType arrays — populated instead of empty
47
+ - `navigator.languages` — realistic value
48
+ - `window.outerWidth/Height` — matches viewport
49
+ - Canvas and WebGL fingerprints — some randomization
50
+
51
+ ---
52
+
53
+ ## Use a Real Browser Profile (Non-Headless)
54
+
55
+ If stealth mode isn't enough, launch with a real user data directory so the browser
56
+ has history, cookies, and extensions like a real user:
57
+
58
+ ```python
59
+ import os
60
+ from playwright.sync_api import sync_playwright
61
+
62
+ user_data = os.path.expanduser("~/.config/captcha-automation-profile")
63
+
64
+ with sync_playwright() as p:
65
+ browser = p.chromium.launch_persistent_context(
66
+ user_data_dir=user_data,
67
+ headless=False, # visible window bypasses some checks
68
+ args=["--disable-blink-features=AutomationControlled"],
69
+ )
70
+ page = browser.new_page()
71
+ page.goto("https://example.com")
72
+ ```
73
+
74
+ The `--disable-blink-features=AutomationControlled` flag prevents the
75
+ `navigator.webdriver` property from being set to `true`.
76
+
77
+ ---
78
+
79
+ ## Realistic Request Headers
80
+
81
+ Missing or wrong headers are a major signal. Set these before navigating:
82
+
83
+ ```python
84
+ page.set_extra_http_headers({
85
+ "Accept-Language": "en-US,en;q=0.9",
86
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
87
+ "Sec-Fetch-Site": "none",
88
+ "Sec-Fetch-Mode": "navigate",
89
+ "Sec-Fetch-User": "?1",
90
+ "Sec-Fetch-Dest": "document",
91
+ "Upgrade-Insecure-Requests": "1",
92
+ })
93
+ ```
94
+
95
+ Also set a realistic User-Agent:
96
+ ```python
97
+ browser = p.chromium.launch()
98
+ context = browser.new_context(
99
+ user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
100
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
101
+ "Chrome/124.0.0.0 Safari/537.36",
102
+ viewport={"width": 1280, "height": 720},
103
+ locale="en-US",
104
+ timezone_id="America/New_York",
105
+ )
106
+ page = context.new_page()
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Add Human-Like Delays
112
+
113
+ ```python
114
+ import time, random
115
+
116
+ def human_delay(min_ms=800, max_ms=2500):
117
+ """Sleep for a random human-like duration."""
118
+ time.sleep(random.uniform(min_ms, max_ms) / 1000)
119
+
120
+ # Between navigation and form fill
121
+ page.goto(url)
122
+ human_delay(1000, 3000)
123
+
124
+ # Between filling each field
125
+ page.fill('#email', 'user@example.com')
126
+ human_delay(300, 900)
127
+ page.fill('#password', 'secret')
128
+ human_delay(500, 1500)
129
+
130
+ # After CAPTCHA solve, before form submit
131
+ inject_captcha_token(page, token)
132
+ human_delay(800, 2000)
133
+ page.click('button[type=submit]')
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Mouse Movement Simulation
139
+
140
+ Sites sometimes require mouse activity before accepting a form submit:
141
+
142
+ ```python
143
+ import asyncio, random, math
144
+
145
+ async def move_mouse_naturally(page, x_end, y_end, steps=20):
146
+ """Simulate curved mouse movement to a target."""
147
+ box = await page.evaluate("({x: window.innerWidth/2, y: window.innerHeight/2})")
148
+ x_start, y_start = box["x"], box["y"]
149
+
150
+ for i in range(steps):
151
+ t = i / steps
152
+ # Quadratic bezier curve
153
+ cx = x_start + random.randint(-50, 50)
154
+ cy = y_start + random.randint(-50, 50)
155
+ x = (1-t)**2 * x_start + 2*(1-t)*t * cx + t**2 * x_end
156
+ y = (1-t)**2 * y_start + 2*(1-t)*t * cy + t**2 * y_end
157
+ await page.mouse.move(x, y)
158
+ await asyncio.sleep(random.uniform(0.01, 0.04))
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Residential Proxies
164
+
165
+ Data center IPs (AWS, GCP, Azure, VPS) are pre-flagged by most anti-bot systems.
166
+ Use residential proxies for better success rates:
167
+
168
+ ```python
169
+ browser = p.chromium.launch(
170
+ proxy={
171
+ "server": "http://proxy.provider.com:8080",
172
+ "username": "user",
173
+ "password": "pass",
174
+ }
175
+ )
176
+ ```
177
+
178
+ Residential proxy providers: Bright Data, Oxylabs, Smartproxy, IPRoyal.
179
+ Expect to pay $5–$15/GB for residential IPs vs $0.50/GB for data center IPs.
180
+
181
+ ---
182
+
183
+ ## Viewport and Screen Size
184
+
185
+ Headless browsers default to unusual viewport sizes. Match common desktop dimensions:
186
+
187
+ ```python
188
+ context = browser.new_context(
189
+ viewport={"width": 1920, "height": 1080},
190
+ device_scale_factor=1,
191
+ is_mobile=False,
192
+ )
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Session Warmup
198
+
199
+ Fresh sessions with no cookies or history are suspicious. Before hitting the target page:
200
+
201
+ 1. Navigate to the homepage first
202
+ 2. Wait a few seconds
203
+ 3. Click a link or scroll
204
+ 4. Then go to the page you want to interact with
205
+
206
+ ```python
207
+ page.goto("https://example.com")
208
+ time.sleep(random.uniform(2, 5))
209
+ # scroll down a bit
210
+ page.evaluate("window.scrollBy(0, Math.floor(Math.random() * 300 + 100))")
211
+ time.sleep(random.uniform(1, 3))
212
+ page.goto("https://example.com/login")
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Detection Test
218
+
219
+ Before automating a target site, test your browser fingerprint at:
220
+ - https://bot.sannysoft.com — headless Chrome detection tests
221
+ - https://pixelscan.net — comprehensive fingerprint check
222
+ - https://abrahamjuliot.github.io/creepjs/ — advanced entropy fingerprinting
223
+
224
+ If these sites detect you as a bot, apply more stealth measures before attempting
225
+ the actual target.
226
+
227
+ ---
228
+
229
+ ## Summary Checklist
230
+
231
+ - [ ] Use `playwright-stealth` (or `--disable-blink-features=AutomationControlled`)
232
+ - [ ] Set realistic User-Agent, viewport, locale, timezone
233
+ - [ ] Set Accept-Language and other headers
234
+ - [ ] Add random delays between actions (800ms–3s)
235
+ - [ ] Move mouse before clicking submit
236
+ - [ ] Use residential proxy if data center IP is blocked
237
+ - [ ] Warm up session before hitting the CAPTCHA page
238
+ - [ ] Inject CAPTCHA token and wait 1–2s before submitting