snaprender 0.7.0__tar.gz → 0.7.2__tar.gz

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.
@@ -0,0 +1,457 @@
1
+ Metadata-Version: 2.1
2
+ Name: snaprender
3
+ Version: 0.7.2
4
+ Summary: Official Python SDK for SnapRender Screenshot API
5
+ Project-URL: Homepage, https://snap-render.com
6
+ Project-URL: Documentation, https://snap-render.com/docs
7
+ Project-URL: Repository, https://github.com/User0856/snaprender
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: api,capture,screenshot,snaprender,webpage
11
+ Requires-Python: >=3.8
12
+ Requires-Dist: httpx>=0.24
13
+ Description-Content-Type: text/markdown
14
+
15
+ # snaprender
16
+
17
+ [![PyPI version](https://img.shields.io/pypi/v/snaprender)](https://pypi.org/project/snaprender/)
18
+ [![PyPI downloads](https://img.shields.io/pypi/dm/snaprender)](https://pypi.org/project/snaprender/)
19
+ [![license](https://img.shields.io/pypi/l/snaprender)](https://github.com/User0856/snaprender/blob/main/LICENSE)
20
+
21
+ Official Python SDK for the [SnapRender](https://snap-render.com) Screenshot API. Capture pixel-perfect screenshots, extract page content, run batch jobs, and manage webhooks with a single library.
22
+
23
+ **500 free screenshots/month. [Get your API key](https://snap-render.com/auth/signup?ref=pypi)**
24
+
25
+ ## Features
26
+
27
+ - **Multiple output formats** : PNG, JPEG, WebP, and PDF
28
+ - **Three input modes** : URL, raw HTML, or Markdown
29
+ - **Signed URLs** : generate pre-signed screenshot URLs (no API key needed at render time)
30
+ - **Content extraction** : pull Markdown, plain text, HTML, article, links, or metadata from any page
31
+ - **Batch screenshots** : capture up to 50 URLs in a single job
32
+ - **Webhooks** : receive real-time notifications for screenshot and quota events
33
+ - **Device emulation** : iPhone, iPad, Pixel, and more presets
34
+ - **Dark mode** : capture pages with `prefers-color-scheme: dark`
35
+ - **Ad blocking** : remove ads automatically before capture
36
+ - **Cookie banner removal** : clean screenshots without consent popups
37
+ - **Smart caching** : configurable CDN cache with TTL control
38
+ - **Full-page captures** : screenshot the entire scrollable page
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ pip install snaprender
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ```python
49
+ from snaprender import SnapRender
50
+
51
+ snap = SnapRender(api_key="sk_live_...")
52
+
53
+ # Capture by URL
54
+ image = snap.capture("https://example.com")
55
+ with open("screenshot.png", "wb") as f:
56
+ f.write(image)
57
+
58
+ # Capture from raw HTML
59
+ image = snap.capture(html="<h1>Hello World</h1>")
60
+
61
+ # Capture from Markdown
62
+ image = snap.capture(markdown="# Hello World\nSome **bold** text.")
63
+ ```
64
+
65
+ > **Cache is OFF by default.** Every request captures a fresh screenshot. To save credits on repeated requests, pass `cache=True`. Cached hits are free and return in under 200ms:
66
+ >
67
+ > ```python
68
+ > image = snap.capture("https://example.com", cache=True)
69
+ > ```
70
+
71
+ ## Context Manager
72
+
73
+ ```python
74
+ with SnapRender(api_key="sk_live_...") as snap:
75
+ image = snap.capture("https://example.com")
76
+ ```
77
+
78
+ The HTTP connection is closed automatically when the block exits.
79
+
80
+ ## API Reference
81
+
82
+ ### Constructor
83
+
84
+ ```python
85
+ SnapRender(api_key, base_url="https://app.snap-render.com", timeout=60.0)
86
+ ```
87
+
88
+ | Parameter | Type | Default | Description |
89
+ |-----------|------|---------|-------------|
90
+ | `api_key` | str | (required) | Your SnapRender API key (`sk_live_...`) |
91
+ | `base_url` | str | `"https://app.snap-render.com"` | API base URL |
92
+ | `timeout` | float | `60.0` | Request timeout in seconds |
93
+
94
+ ---
95
+
96
+ ### `snap.capture(url, *, html, markdown, **options)` -> `bytes | dict`
97
+
98
+ Take a screenshot. Provide exactly **one** of `url`, `html`, or `markdown`.
99
+
100
+ - When `url` is provided alone, the request is sent as GET with query parameters.
101
+ - When `html` or `markdown` is provided, the request is sent as POST with a JSON body.
102
+ - Returns raw image bytes by default. Set `response_type="json"` to get a dict with metadata and a base64 data URI.
103
+
104
+ ```python
105
+ # URL with options
106
+ jpg = snap.capture(
107
+ "https://example.com",
108
+ format="jpeg",
109
+ width=1920,
110
+ height=1080,
111
+ full_page=True,
112
+ dark_mode=True,
113
+ quality=95,
114
+ )
115
+
116
+ # HTML input
117
+ png = snap.capture(html="<h1 style='color:red'>Red Title</h1>", width=800)
118
+
119
+ # Markdown input
120
+ png = snap.capture(markdown="# Report\n\n| Col A | Col B |\n|-------|-------|\n| 1 | 2 |")
121
+
122
+ # JSON response (base64 data URI + metadata)
123
+ result = snap.capture("https://example.com", response_type="json")
124
+ print(result["image"]) # data:image/png;base64,...
125
+ ```
126
+
127
+ **Options**
128
+
129
+ | Option | Type | Default | Description |
130
+ |--------|------|---------|-------------|
131
+ | `url` | str | `None` | URL to capture |
132
+ | `html` | str | `None` | Raw HTML to render |
133
+ | `markdown` | str | `None` | Markdown to render |
134
+ | `format` | str | `"png"` | `"png"`, `"jpeg"`, `"webp"`, or `"pdf"` |
135
+ | `width` | int | `1280` | Viewport width in pixels |
136
+ | `height` | int | `800` | Viewport height in pixels |
137
+ | `full_page` | bool | `False` | Capture the full scrollable page |
138
+ | `quality` | int | `90` | JPEG/WebP quality (1-100) |
139
+ | `delay` | int | `0` | Wait (ms) after page load before capture |
140
+ | `dark_mode` | bool | `False` | Emulate dark color scheme |
141
+ | `block_ads` | bool | `True` | Block ad networks |
142
+ | `block_cookie_banners` | bool | `True` | Remove cookie consent banners |
143
+ | `device` | str | `None` | Device preset: `"iphone_14"`, `"iphone_15_pro"`, `"pixel_7"`, `"ipad_pro"`, `"macbook_pro"` |
144
+ | `hide_selectors` | str | `None` | Comma-separated CSS selectors to hide |
145
+ | `click_selector` | str | `None` | CSS selector to click before capture |
146
+ | `user_agent` | str | `None` | Custom user-agent string |
147
+ | `cache` | bool | `False` | Return cached result if available. **Off by default:** set `True` to enable caching. Cached hits are free but may be up to 24h old. |
148
+ | `cache_ttl` | int | `86400` | Cache lifetime in seconds (default 24h). Cached screenshots older than this are recaptured. |
149
+ | `response_type` | str | `None` | Set to `"json"` for metadata + base64 data URI |
150
+
151
+ ---
152
+
153
+ ### `snap.sign(url, *, expires_in, **options)` -> `dict`
154
+
155
+ Generate a signed URL that can be used without an API key. Signing itself is free and does not count against your quota. One credit is consumed when the signed URL is rendered.
156
+
157
+ ```python
158
+ result = snap.sign(
159
+ "https://example.com",
160
+ expires_in=3600, # optional, seconds until expiry
161
+ format="png",
162
+ width=1280,
163
+ dark_mode=True,
164
+ )
165
+ print(result["signed_url"]) # use this in <img> tags, emails, etc.
166
+ print(result["expires_at"]) # ISO 8601 timestamp
167
+ ```
168
+
169
+ **Options**
170
+
171
+ | Option | Type | Default | Description |
172
+ |--------|------|---------|-------------|
173
+ | `url` | str | (required) | URL to capture |
174
+ | `expires_in` | int | `None` | Seconds until the signed URL expires |
175
+ | `format` | str | `None` | `"png"`, `"jpeg"`, `"webp"`, or `"pdf"` |
176
+ | `width` | int | `None` | Viewport width |
177
+ | `height` | int | `None` | Viewport height |
178
+ | `full_page` | bool | `None` | Full-page capture |
179
+ | `quality` | int | `None` | JPEG/WebP quality |
180
+ | `delay` | int | `None` | Wait (ms) after load |
181
+ | `dark_mode` | bool | `None` | Emulate dark mode |
182
+ | `block_ads` | bool | `None` | Block ads |
183
+ | `block_cookie_banners` | bool | `None` | Remove cookie banners |
184
+ | `hide_selectors` | str | `None` | CSS selectors to hide |
185
+ | `click_selector` | str | `None` | CSS selector to click |
186
+ | `device` | str | `None` | Device preset |
187
+ | `user_agent` | str | `None` | Custom user-agent |
188
+
189
+ **Returns** `{ "signed_url": str, "expires_at": str, "expires_in": int }`
190
+
191
+ ---
192
+
193
+ ### `snap.extract(url, *, type, **options)` -> `dict`
194
+
195
+ Extract content from a web page. Six extraction types are available:
196
+
197
+ | Type | Description |
198
+ |------|-------------|
199
+ | `"markdown"` | Page content converted to Markdown (default) |
200
+ | `"text"` | Plain text, all tags stripped |
201
+ | `"html"` | Cleaned HTML |
202
+ | `"article"` | Article body extracted via Readability |
203
+ | `"links"` | All links on the page |
204
+ | `"metadata"` | Title, description, Open Graph tags, etc. |
205
+
206
+ ```python
207
+ # Extract as Markdown
208
+ result = snap.extract("https://example.com", type="markdown")
209
+ print(result["content"])
210
+ print(result["wordCount"])
211
+
212
+ # Extract just the article body
213
+ article = snap.extract("https://example.com/blog/post", type="article")
214
+
215
+ # Extract metadata
216
+ meta = snap.extract("https://example.com", type="metadata")
217
+
218
+ # Scope extraction to a specific element
219
+ result = snap.extract(
220
+ "https://example.com",
221
+ type="text",
222
+ selector="#main-content",
223
+ max_length=5000,
224
+ )
225
+ ```
226
+
227
+ **Options**
228
+
229
+ | Option | Type | Default | Description |
230
+ |--------|------|---------|-------------|
231
+ | `url` | str | (required) | URL to extract from |
232
+ | `type` | str | `"markdown"` | Extraction type (see table above) |
233
+ | `selector` | str | `None` | CSS selector to scope extraction |
234
+ | `block_ads` | bool | `None` | Block ads before extraction |
235
+ | `block_cookie_banners` | bool | `None` | Remove cookie banners |
236
+ | `delay` | int | `None` | Wait (ms) after page load |
237
+ | `max_length` | int | `None` | Truncate content to this many characters |
238
+ | `cache` | bool | `None` | Return cached extraction if available. **Off by default:** set `True` to enable caching. Cached hits are free but may be stale. |
239
+ | `cache_ttl` | int | `None` | Cache lifetime in seconds (default 24h). |
240
+
241
+ **Returns** `{ "url": str, "type": str, "content": ..., "wordCount": int, "processingTimeMs": int }`
242
+
243
+ ---
244
+
245
+ ### `snap.batch(urls, **options)` -> `dict`
246
+
247
+ Create a batch screenshot job for 1 to 50 URLs. The call returns immediately with a job ID. Each URL consumes one credit; credits for failed URLs are rolled back.
248
+
249
+ ```python
250
+ job = snap.batch(
251
+ ["https://example.com", "https://example.org", "https://example.net"],
252
+ format="png",
253
+ width=1280,
254
+ dark_mode=True,
255
+ )
256
+ print(job["job_id"]) # use this to poll status
257
+ ```
258
+
259
+ **Options**: same screenshot options as `capture()` (except `url`, `html`, `markdown`, `response_type`, `cache`, `cache_ttl`). These options apply to every URL in the batch.
260
+
261
+ **Returns** `{ "job_id": str, "status": str, "total": int, ... }`
262
+
263
+ ---
264
+
265
+ ### `snap.get_batch_status(job_id)` -> `dict`
266
+
267
+ Poll the status of a batch job. Keep polling until `status` is `"completed"` or `"failed"`.
268
+
269
+ ```python
270
+ import time
271
+
272
+ job = snap.batch(["https://example.com", "https://example.org"])
273
+
274
+ while True:
275
+ status = snap.get_batch_status(job["job_id"])
276
+ print(f"{status['status']} - {status.get('completed', 0)}/{status['total']}")
277
+ if status["status"] in ("completed", "failed"):
278
+ break
279
+ time.sleep(2)
280
+
281
+ # Download results
282
+ for result in status["results"]:
283
+ print(result["url"], result["download_url"])
284
+ ```
285
+
286
+ ---
287
+
288
+ ### `snap.create_webhook(url, events)` -> `dict`
289
+
290
+ Register a webhook endpoint to receive event notifications. Maximum 5 webhooks per account.
291
+
292
+ Available events: `screenshot.completed`, `quota.warning`, `quota.exceeded`
293
+
294
+ ```python
295
+ webhook = snap.create_webhook(
296
+ url="https://yoursite.com/webhooks/snaprender",
297
+ events=["screenshot.completed", "quota.warning"],
298
+ )
299
+ print(webhook["id"])
300
+ print(webhook["secret"]) # save this for signature verification
301
+ ```
302
+
303
+ ---
304
+
305
+ ### `snap.list_webhooks()` -> `list[dict]`
306
+
307
+ List all webhooks registered on your account.
308
+
309
+ ```python
310
+ webhooks = snap.list_webhooks()
311
+ for wh in webhooks:
312
+ print(wh["id"], wh["url"], wh["events"])
313
+ ```
314
+
315
+ ---
316
+
317
+ ### `snap.delete_webhook(webhook_id)` -> `None`
318
+
319
+ Delete a webhook by its ID.
320
+
321
+ ```python
322
+ snap.delete_webhook("wh_abc123")
323
+ ```
324
+
325
+ ---
326
+
327
+ ### `snap.test_webhook(webhook_id)` -> `dict`
328
+
329
+ Send a test payload to a webhook endpoint. Useful for verifying your handler works before relying on real events.
330
+
331
+ ```python
332
+ result = snap.test_webhook("wh_abc123")
333
+ print(result) # delivery status
334
+ ```
335
+
336
+ ---
337
+
338
+ ### `SnapRender.verify_webhook_signature(payload, signature, secret)` -> `bool`
339
+
340
+ Static method. Verify the HMAC-SHA256 signature of an incoming webhook payload. Use this in your webhook handler to confirm the request was sent by SnapRender.
341
+
342
+ ```python
343
+ from snaprender import SnapRender
344
+
345
+ # In your webhook handler (e.g., Flask)
346
+ @app.route("/webhooks/snaprender", methods=["POST"])
347
+ def handle_webhook():
348
+ payload = request.get_data(as_text=True)
349
+ signature = request.headers.get("X-Signature")
350
+ secret = "whsec_..." # from create_webhook response
351
+
352
+ if not SnapRender.verify_webhook_signature(payload, signature, secret):
353
+ return "Invalid signature", 403
354
+
355
+ event = request.get_json()
356
+ print(event["type"], event["data"])
357
+ return "OK", 200
358
+ ```
359
+
360
+ ---
361
+
362
+ ### `snap.info(url)` -> `dict`
363
+
364
+ Check if a screenshot is cached for a given URL, without capturing it. No credits are consumed.
365
+
366
+ ```python
367
+ info = snap.info("https://example.com")
368
+ print(info["cached"]) # True or False
369
+ print(info["expires_at"]) # ISO timestamp (when cached)
370
+ ```
371
+
372
+ **Returns** `{ "url": str, "cached": bool, "cache_key": str | None, "cached_at": str | None, "expires_at": str | None, "content_type": str | None }`
373
+
374
+ ---
375
+
376
+ ### `snap.usage()` -> `dict`
377
+
378
+ Get the current billing period's usage summary.
379
+
380
+ ```python
381
+ usage = snap.usage()
382
+ print(f"{usage['used']}/{usage['limit']} screenshots used")
383
+ print(f"Plan: {usage['plan']}, Remaining: {usage['remaining']}")
384
+ ```
385
+
386
+ **Returns** `{ "plan": str, "used": int, "limit": int, "remaining": int, "period": dict }`
387
+
388
+ ---
389
+
390
+ ### `snap.usage_daily(days=30)` -> `dict`
391
+
392
+ Get a day-by-day usage breakdown.
393
+
394
+ ```python
395
+ daily = snap.usage_daily(days=7)
396
+ for day in daily["daily"]:
397
+ print(day["date"], day["count"])
398
+ ```
399
+
400
+ | Parameter | Type | Default | Description |
401
+ |-----------|------|---------|-------------|
402
+ | `days` | int | `30` | Number of days to include |
403
+
404
+ ---
405
+
406
+ ## LangChain Integration
407
+
408
+ Use SnapRender as a [LangChain](https://python.langchain.com/) tool for AI agents:
409
+
410
+ ```python
411
+ import os
412
+ from langchain_core.tools import tool
413
+ from snaprender import SnapRender
414
+
415
+ client = SnapRender(api_key=os.environ["SNAPRENDER_API_KEY"])
416
+
417
+ @tool
418
+ def take_screenshot(url: str, format: str = "png", dark_mode: bool = False) -> str:
419
+ """Capture a screenshot of any website URL. Returns base64 data URI."""
420
+ result = client.capture(
421
+ url, format=format, dark_mode=dark_mode, response_type="json"
422
+ )
423
+ return result["image"]
424
+ ```
425
+
426
+ Works with LangGraph, CrewAI, and any framework that supports LangChain tools.
427
+
428
+ ## Error Handling
429
+
430
+ All API errors raise `SnapRenderError` with `code`, `status`, and a human-readable message.
431
+
432
+ ```python
433
+ from snaprender import SnapRender, SnapRenderError
434
+
435
+ snap = SnapRender(api_key="sk_live_...")
436
+
437
+ try:
438
+ snap.capture("https://example.com")
439
+ except SnapRenderError as e:
440
+ print(e.code) # "QUOTA_EXCEEDED"
441
+ print(e.status) # 429
442
+ print(e) # "Monthly quota exceeded"
443
+ ```
444
+
445
+ Common error codes: `INVALID_API_KEY`, `QUOTA_EXCEEDED`, `INVALID_URL`, `VALIDATION_ERROR`, `SCREENSHOT_FAILED`.
446
+
447
+ ## Links
448
+
449
+ - [Documentation](https://snap-render.com/docs)
450
+ - [Pricing](https://snap-render.com/pricing)
451
+ - [Dashboard](https://app.snap-render.com/dashboard)
452
+ - [Blog](https://snap-render.com/blog)
453
+ - [GitHub](https://github.com/User0856/snaprender)
454
+
455
+ ## License
456
+
457
+ MIT
@@ -0,0 +1,443 @@
1
+ # snaprender
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/snaprender)](https://pypi.org/project/snaprender/)
4
+ [![PyPI downloads](https://img.shields.io/pypi/dm/snaprender)](https://pypi.org/project/snaprender/)
5
+ [![license](https://img.shields.io/pypi/l/snaprender)](https://github.com/User0856/snaprender/blob/main/LICENSE)
6
+
7
+ Official Python SDK for the [SnapRender](https://snap-render.com) Screenshot API. Capture pixel-perfect screenshots, extract page content, run batch jobs, and manage webhooks with a single library.
8
+
9
+ **500 free screenshots/month. [Get your API key](https://snap-render.com/auth/signup?ref=pypi)**
10
+
11
+ ## Features
12
+
13
+ - **Multiple output formats** : PNG, JPEG, WebP, and PDF
14
+ - **Three input modes** : URL, raw HTML, or Markdown
15
+ - **Signed URLs** : generate pre-signed screenshot URLs (no API key needed at render time)
16
+ - **Content extraction** : pull Markdown, plain text, HTML, article, links, or metadata from any page
17
+ - **Batch screenshots** : capture up to 50 URLs in a single job
18
+ - **Webhooks** : receive real-time notifications for screenshot and quota events
19
+ - **Device emulation** : iPhone, iPad, Pixel, and more presets
20
+ - **Dark mode** : capture pages with `prefers-color-scheme: dark`
21
+ - **Ad blocking** : remove ads automatically before capture
22
+ - **Cookie banner removal** : clean screenshots without consent popups
23
+ - **Smart caching** : configurable CDN cache with TTL control
24
+ - **Full-page captures** : screenshot the entire scrollable page
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pip install snaprender
30
+ ```
31
+
32
+ ## Quick Start
33
+
34
+ ```python
35
+ from snaprender import SnapRender
36
+
37
+ snap = SnapRender(api_key="sk_live_...")
38
+
39
+ # Capture by URL
40
+ image = snap.capture("https://example.com")
41
+ with open("screenshot.png", "wb") as f:
42
+ f.write(image)
43
+
44
+ # Capture from raw HTML
45
+ image = snap.capture(html="<h1>Hello World</h1>")
46
+
47
+ # Capture from Markdown
48
+ image = snap.capture(markdown="# Hello World\nSome **bold** text.")
49
+ ```
50
+
51
+ > **Cache is OFF by default.** Every request captures a fresh screenshot. To save credits on repeated requests, pass `cache=True`. Cached hits are free and return in under 200ms:
52
+ >
53
+ > ```python
54
+ > image = snap.capture("https://example.com", cache=True)
55
+ > ```
56
+
57
+ ## Context Manager
58
+
59
+ ```python
60
+ with SnapRender(api_key="sk_live_...") as snap:
61
+ image = snap.capture("https://example.com")
62
+ ```
63
+
64
+ The HTTP connection is closed automatically when the block exits.
65
+
66
+ ## API Reference
67
+
68
+ ### Constructor
69
+
70
+ ```python
71
+ SnapRender(api_key, base_url="https://app.snap-render.com", timeout=60.0)
72
+ ```
73
+
74
+ | Parameter | Type | Default | Description |
75
+ |-----------|------|---------|-------------|
76
+ | `api_key` | str | (required) | Your SnapRender API key (`sk_live_...`) |
77
+ | `base_url` | str | `"https://app.snap-render.com"` | API base URL |
78
+ | `timeout` | float | `60.0` | Request timeout in seconds |
79
+
80
+ ---
81
+
82
+ ### `snap.capture(url, *, html, markdown, **options)` -> `bytes | dict`
83
+
84
+ Take a screenshot. Provide exactly **one** of `url`, `html`, or `markdown`.
85
+
86
+ - When `url` is provided alone, the request is sent as GET with query parameters.
87
+ - When `html` or `markdown` is provided, the request is sent as POST with a JSON body.
88
+ - Returns raw image bytes by default. Set `response_type="json"` to get a dict with metadata and a base64 data URI.
89
+
90
+ ```python
91
+ # URL with options
92
+ jpg = snap.capture(
93
+ "https://example.com",
94
+ format="jpeg",
95
+ width=1920,
96
+ height=1080,
97
+ full_page=True,
98
+ dark_mode=True,
99
+ quality=95,
100
+ )
101
+
102
+ # HTML input
103
+ png = snap.capture(html="<h1 style='color:red'>Red Title</h1>", width=800)
104
+
105
+ # Markdown input
106
+ png = snap.capture(markdown="# Report\n\n| Col A | Col B |\n|-------|-------|\n| 1 | 2 |")
107
+
108
+ # JSON response (base64 data URI + metadata)
109
+ result = snap.capture("https://example.com", response_type="json")
110
+ print(result["image"]) # data:image/png;base64,...
111
+ ```
112
+
113
+ **Options**
114
+
115
+ | Option | Type | Default | Description |
116
+ |--------|------|---------|-------------|
117
+ | `url` | str | `None` | URL to capture |
118
+ | `html` | str | `None` | Raw HTML to render |
119
+ | `markdown` | str | `None` | Markdown to render |
120
+ | `format` | str | `"png"` | `"png"`, `"jpeg"`, `"webp"`, or `"pdf"` |
121
+ | `width` | int | `1280` | Viewport width in pixels |
122
+ | `height` | int | `800` | Viewport height in pixels |
123
+ | `full_page` | bool | `False` | Capture the full scrollable page |
124
+ | `quality` | int | `90` | JPEG/WebP quality (1-100) |
125
+ | `delay` | int | `0` | Wait (ms) after page load before capture |
126
+ | `dark_mode` | bool | `False` | Emulate dark color scheme |
127
+ | `block_ads` | bool | `True` | Block ad networks |
128
+ | `block_cookie_banners` | bool | `True` | Remove cookie consent banners |
129
+ | `device` | str | `None` | Device preset: `"iphone_14"`, `"iphone_15_pro"`, `"pixel_7"`, `"ipad_pro"`, `"macbook_pro"` |
130
+ | `hide_selectors` | str | `None` | Comma-separated CSS selectors to hide |
131
+ | `click_selector` | str | `None` | CSS selector to click before capture |
132
+ | `user_agent` | str | `None` | Custom user-agent string |
133
+ | `cache` | bool | `False` | Return cached result if available. **Off by default:** set `True` to enable caching. Cached hits are free but may be up to 24h old. |
134
+ | `cache_ttl` | int | `86400` | Cache lifetime in seconds (default 24h). Cached screenshots older than this are recaptured. |
135
+ | `response_type` | str | `None` | Set to `"json"` for metadata + base64 data URI |
136
+
137
+ ---
138
+
139
+ ### `snap.sign(url, *, expires_in, **options)` -> `dict`
140
+
141
+ Generate a signed URL that can be used without an API key. Signing itself is free and does not count against your quota. One credit is consumed when the signed URL is rendered.
142
+
143
+ ```python
144
+ result = snap.sign(
145
+ "https://example.com",
146
+ expires_in=3600, # optional, seconds until expiry
147
+ format="png",
148
+ width=1280,
149
+ dark_mode=True,
150
+ )
151
+ print(result["signed_url"]) # use this in <img> tags, emails, etc.
152
+ print(result["expires_at"]) # ISO 8601 timestamp
153
+ ```
154
+
155
+ **Options**
156
+
157
+ | Option | Type | Default | Description |
158
+ |--------|------|---------|-------------|
159
+ | `url` | str | (required) | URL to capture |
160
+ | `expires_in` | int | `None` | Seconds until the signed URL expires |
161
+ | `format` | str | `None` | `"png"`, `"jpeg"`, `"webp"`, or `"pdf"` |
162
+ | `width` | int | `None` | Viewport width |
163
+ | `height` | int | `None` | Viewport height |
164
+ | `full_page` | bool | `None` | Full-page capture |
165
+ | `quality` | int | `None` | JPEG/WebP quality |
166
+ | `delay` | int | `None` | Wait (ms) after load |
167
+ | `dark_mode` | bool | `None` | Emulate dark mode |
168
+ | `block_ads` | bool | `None` | Block ads |
169
+ | `block_cookie_banners` | bool | `None` | Remove cookie banners |
170
+ | `hide_selectors` | str | `None` | CSS selectors to hide |
171
+ | `click_selector` | str | `None` | CSS selector to click |
172
+ | `device` | str | `None` | Device preset |
173
+ | `user_agent` | str | `None` | Custom user-agent |
174
+
175
+ **Returns** `{ "signed_url": str, "expires_at": str, "expires_in": int }`
176
+
177
+ ---
178
+
179
+ ### `snap.extract(url, *, type, **options)` -> `dict`
180
+
181
+ Extract content from a web page. Six extraction types are available:
182
+
183
+ | Type | Description |
184
+ |------|-------------|
185
+ | `"markdown"` | Page content converted to Markdown (default) |
186
+ | `"text"` | Plain text, all tags stripped |
187
+ | `"html"` | Cleaned HTML |
188
+ | `"article"` | Article body extracted via Readability |
189
+ | `"links"` | All links on the page |
190
+ | `"metadata"` | Title, description, Open Graph tags, etc. |
191
+
192
+ ```python
193
+ # Extract as Markdown
194
+ result = snap.extract("https://example.com", type="markdown")
195
+ print(result["content"])
196
+ print(result["wordCount"])
197
+
198
+ # Extract just the article body
199
+ article = snap.extract("https://example.com/blog/post", type="article")
200
+
201
+ # Extract metadata
202
+ meta = snap.extract("https://example.com", type="metadata")
203
+
204
+ # Scope extraction to a specific element
205
+ result = snap.extract(
206
+ "https://example.com",
207
+ type="text",
208
+ selector="#main-content",
209
+ max_length=5000,
210
+ )
211
+ ```
212
+
213
+ **Options**
214
+
215
+ | Option | Type | Default | Description |
216
+ |--------|------|---------|-------------|
217
+ | `url` | str | (required) | URL to extract from |
218
+ | `type` | str | `"markdown"` | Extraction type (see table above) |
219
+ | `selector` | str | `None` | CSS selector to scope extraction |
220
+ | `block_ads` | bool | `None` | Block ads before extraction |
221
+ | `block_cookie_banners` | bool | `None` | Remove cookie banners |
222
+ | `delay` | int | `None` | Wait (ms) after page load |
223
+ | `max_length` | int | `None` | Truncate content to this many characters |
224
+ | `cache` | bool | `None` | Return cached extraction if available. **Off by default:** set `True` to enable caching. Cached hits are free but may be stale. |
225
+ | `cache_ttl` | int | `None` | Cache lifetime in seconds (default 24h). |
226
+
227
+ **Returns** `{ "url": str, "type": str, "content": ..., "wordCount": int, "processingTimeMs": int }`
228
+
229
+ ---
230
+
231
+ ### `snap.batch(urls, **options)` -> `dict`
232
+
233
+ Create a batch screenshot job for 1 to 50 URLs. The call returns immediately with a job ID. Each URL consumes one credit; credits for failed URLs are rolled back.
234
+
235
+ ```python
236
+ job = snap.batch(
237
+ ["https://example.com", "https://example.org", "https://example.net"],
238
+ format="png",
239
+ width=1280,
240
+ dark_mode=True,
241
+ )
242
+ print(job["job_id"]) # use this to poll status
243
+ ```
244
+
245
+ **Options**: same screenshot options as `capture()` (except `url`, `html`, `markdown`, `response_type`, `cache`, `cache_ttl`). These options apply to every URL in the batch.
246
+
247
+ **Returns** `{ "job_id": str, "status": str, "total": int, ... }`
248
+
249
+ ---
250
+
251
+ ### `snap.get_batch_status(job_id)` -> `dict`
252
+
253
+ Poll the status of a batch job. Keep polling until `status` is `"completed"` or `"failed"`.
254
+
255
+ ```python
256
+ import time
257
+
258
+ job = snap.batch(["https://example.com", "https://example.org"])
259
+
260
+ while True:
261
+ status = snap.get_batch_status(job["job_id"])
262
+ print(f"{status['status']} - {status.get('completed', 0)}/{status['total']}")
263
+ if status["status"] in ("completed", "failed"):
264
+ break
265
+ time.sleep(2)
266
+
267
+ # Download results
268
+ for result in status["results"]:
269
+ print(result["url"], result["download_url"])
270
+ ```
271
+
272
+ ---
273
+
274
+ ### `snap.create_webhook(url, events)` -> `dict`
275
+
276
+ Register a webhook endpoint to receive event notifications. Maximum 5 webhooks per account.
277
+
278
+ Available events: `screenshot.completed`, `quota.warning`, `quota.exceeded`
279
+
280
+ ```python
281
+ webhook = snap.create_webhook(
282
+ url="https://yoursite.com/webhooks/snaprender",
283
+ events=["screenshot.completed", "quota.warning"],
284
+ )
285
+ print(webhook["id"])
286
+ print(webhook["secret"]) # save this for signature verification
287
+ ```
288
+
289
+ ---
290
+
291
+ ### `snap.list_webhooks()` -> `list[dict]`
292
+
293
+ List all webhooks registered on your account.
294
+
295
+ ```python
296
+ webhooks = snap.list_webhooks()
297
+ for wh in webhooks:
298
+ print(wh["id"], wh["url"], wh["events"])
299
+ ```
300
+
301
+ ---
302
+
303
+ ### `snap.delete_webhook(webhook_id)` -> `None`
304
+
305
+ Delete a webhook by its ID.
306
+
307
+ ```python
308
+ snap.delete_webhook("wh_abc123")
309
+ ```
310
+
311
+ ---
312
+
313
+ ### `snap.test_webhook(webhook_id)` -> `dict`
314
+
315
+ Send a test payload to a webhook endpoint. Useful for verifying your handler works before relying on real events.
316
+
317
+ ```python
318
+ result = snap.test_webhook("wh_abc123")
319
+ print(result) # delivery status
320
+ ```
321
+
322
+ ---
323
+
324
+ ### `SnapRender.verify_webhook_signature(payload, signature, secret)` -> `bool`
325
+
326
+ Static method. Verify the HMAC-SHA256 signature of an incoming webhook payload. Use this in your webhook handler to confirm the request was sent by SnapRender.
327
+
328
+ ```python
329
+ from snaprender import SnapRender
330
+
331
+ # In your webhook handler (e.g., Flask)
332
+ @app.route("/webhooks/snaprender", methods=["POST"])
333
+ def handle_webhook():
334
+ payload = request.get_data(as_text=True)
335
+ signature = request.headers.get("X-Signature")
336
+ secret = "whsec_..." # from create_webhook response
337
+
338
+ if not SnapRender.verify_webhook_signature(payload, signature, secret):
339
+ return "Invalid signature", 403
340
+
341
+ event = request.get_json()
342
+ print(event["type"], event["data"])
343
+ return "OK", 200
344
+ ```
345
+
346
+ ---
347
+
348
+ ### `snap.info(url)` -> `dict`
349
+
350
+ Check if a screenshot is cached for a given URL, without capturing it. No credits are consumed.
351
+
352
+ ```python
353
+ info = snap.info("https://example.com")
354
+ print(info["cached"]) # True or False
355
+ print(info["expires_at"]) # ISO timestamp (when cached)
356
+ ```
357
+
358
+ **Returns** `{ "url": str, "cached": bool, "cache_key": str | None, "cached_at": str | None, "expires_at": str | None, "content_type": str | None }`
359
+
360
+ ---
361
+
362
+ ### `snap.usage()` -> `dict`
363
+
364
+ Get the current billing period's usage summary.
365
+
366
+ ```python
367
+ usage = snap.usage()
368
+ print(f"{usage['used']}/{usage['limit']} screenshots used")
369
+ print(f"Plan: {usage['plan']}, Remaining: {usage['remaining']}")
370
+ ```
371
+
372
+ **Returns** `{ "plan": str, "used": int, "limit": int, "remaining": int, "period": dict }`
373
+
374
+ ---
375
+
376
+ ### `snap.usage_daily(days=30)` -> `dict`
377
+
378
+ Get a day-by-day usage breakdown.
379
+
380
+ ```python
381
+ daily = snap.usage_daily(days=7)
382
+ for day in daily["daily"]:
383
+ print(day["date"], day["count"])
384
+ ```
385
+
386
+ | Parameter | Type | Default | Description |
387
+ |-----------|------|---------|-------------|
388
+ | `days` | int | `30` | Number of days to include |
389
+
390
+ ---
391
+
392
+ ## LangChain Integration
393
+
394
+ Use SnapRender as a [LangChain](https://python.langchain.com/) tool for AI agents:
395
+
396
+ ```python
397
+ import os
398
+ from langchain_core.tools import tool
399
+ from snaprender import SnapRender
400
+
401
+ client = SnapRender(api_key=os.environ["SNAPRENDER_API_KEY"])
402
+
403
+ @tool
404
+ def take_screenshot(url: str, format: str = "png", dark_mode: bool = False) -> str:
405
+ """Capture a screenshot of any website URL. Returns base64 data URI."""
406
+ result = client.capture(
407
+ url, format=format, dark_mode=dark_mode, response_type="json"
408
+ )
409
+ return result["image"]
410
+ ```
411
+
412
+ Works with LangGraph, CrewAI, and any framework that supports LangChain tools.
413
+
414
+ ## Error Handling
415
+
416
+ All API errors raise `SnapRenderError` with `code`, `status`, and a human-readable message.
417
+
418
+ ```python
419
+ from snaprender import SnapRender, SnapRenderError
420
+
421
+ snap = SnapRender(api_key="sk_live_...")
422
+
423
+ try:
424
+ snap.capture("https://example.com")
425
+ except SnapRenderError as e:
426
+ print(e.code) # "QUOTA_EXCEEDED"
427
+ print(e.status) # 429
428
+ print(e) # "Monthly quota exceeded"
429
+ ```
430
+
431
+ Common error codes: `INVALID_API_KEY`, `QUOTA_EXCEEDED`, `INVALID_URL`, `VALIDATION_ERROR`, `SCREENSHOT_FAILED`.
432
+
433
+ ## Links
434
+
435
+ - [Documentation](https://snap-render.com/docs)
436
+ - [Pricing](https://snap-render.com/pricing)
437
+ - [Dashboard](https://app.snap-render.com/dashboard)
438
+ - [Blog](https://snap-render.com/blog)
439
+ - [GitHub](https://github.com/User0856/snaprender)
440
+
441
+ ## License
442
+
443
+ MIT
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "snaprender"
7
- version = "0.7.0"
7
+ version = "0.7.2"
8
8
  description = "Official Python SDK for SnapRender Screenshot API"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -3,4 +3,4 @@
3
3
  from .client import SnapRender, SnapRenderError
4
4
 
5
5
  __all__ = ["SnapRender", "SnapRenderError"]
6
- __version__ = "0.5.0"
6
+ __version__ = "0.7.2"
snaprender-0.7.0/PKG-INFO DELETED
@@ -1,166 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: snaprender
3
- Version: 0.7.0
4
- Summary: Official Python SDK for SnapRender Screenshot API
5
- Project-URL: Homepage, https://snap-render.com
6
- Project-URL: Documentation, https://snap-render.com/docs
7
- Project-URL: Repository, https://github.com/User0856/snaprender
8
- License: MIT
9
- License-File: LICENSE
10
- Keywords: api,capture,screenshot,snaprender,webpage
11
- Requires-Python: >=3.8
12
- Requires-Dist: httpx>=0.24
13
- Description-Content-Type: text/markdown
14
-
15
- # snaprender
16
-
17
- [![PyPI version](https://img.shields.io/pypi/v/snaprender)](https://pypi.org/project/snaprender/)
18
- [![PyPI downloads](https://img.shields.io/pypi/dm/snaprender)](https://pypi.org/project/snaprender/)
19
- [![license](https://img.shields.io/pypi/l/snaprender)](https://github.com/User0856/snaprender/blob/main/LICENSE)
20
-
21
- Official Python SDK for the [SnapRender](https://snap-render.com) Screenshot API — capture pixel-perfect screenshots of any webpage with a single API call.
22
-
23
- **500 free screenshots/month — [Get your API key](https://snap-render.com/auth/signup?ref=pypi)**
24
-
25
- ## Features
26
-
27
- - **Multiple output formats** — PNG, JPEG, WebP, and PDF
28
- - **Device emulation** — iPhone, iPad, Pixel, and more presets
29
- - **Dark mode** — Capture pages with `prefers-color-scheme: dark`
30
- - **Ad blocking** — Remove ads automatically before capture
31
- - **Cookie banner removal** — Clean screenshots without consent popups
32
- - **Smart caching** — Configurable CDN cache with TTL control
33
- - **Full-page captures** — Screenshot the entire scrollable page
34
-
35
- ## Install
36
-
37
- ```bash
38
- pip install snaprender
39
- ```
40
-
41
- ## Quick Start
42
-
43
- ```python
44
- from snaprender import SnapRender
45
-
46
- snap = SnapRender(api_key="sk_live_...")
47
-
48
- # Capture a screenshot
49
- image = snap.capture("https://example.com")
50
- with open("screenshot.png", "wb") as f:
51
- f.write(image)
52
-
53
- # Capture with options
54
- jpg = snap.capture(
55
- "https://example.com",
56
- format="jpeg",
57
- width=1920,
58
- height=1080,
59
- full_page=True,
60
- dark_mode=True,
61
- quality=95,
62
- )
63
-
64
- # Check cache status
65
- info = snap.info("https://example.com")
66
- print(info["cached"]) # True/False
67
- print(info["expires_at"]) # ISO date string (when cached)
68
-
69
- # Get usage
70
- usage = snap.usage()
71
- print(f"{usage['used']}/{usage['limit']} screenshots used")
72
- ```
73
-
74
- ## Context Manager
75
-
76
- ```python
77
- with SnapRender(api_key="sk_live_...") as snap:
78
- image = snap.capture("https://example.com")
79
- ```
80
-
81
- ## API
82
-
83
- ### `SnapRender(api_key, base_url="https://app.snap-render.com", timeout=60.0)`
84
-
85
- ### `snap.capture(url, **options)` -> `bytes`
86
-
87
- | Option | Type | Default | Description |
88
- |--------|------|---------|-------------|
89
- | `url` | str | — | URL to capture (required) |
90
- | `format` | str | `"png"` | `"png"`, `"jpeg"`, `"webp"`, or `"pdf"` |
91
- | `width` | int | `1280` | Viewport width |
92
- | `height` | int | `800` | Viewport height |
93
- | `full_page` | bool | `False` | Capture full scrollable page |
94
- | `quality` | int | `90` | JPEG/WebP quality (1-100) |
95
- | `delay` | int | `0` | Wait ms after page load |
96
- | `dark_mode` | bool | `False` | Emulate dark mode |
97
- | `block_ads` | bool | `True` | Block ad networks |
98
- | `block_cookie_banners` | bool | `True` | Remove cookie banners |
99
- | `device` | str | — | Device preset (`"iphone_14"`, `"iphone_15_pro"`, `"pixel_7"`, `"ipad_pro"`, `"macbook_pro"`) |
100
- | `hide_selectors` | str | — | Comma-separated CSS selectors to hide |
101
- | `click_selector` | str | — | CSS selector to click before capture |
102
- | `user_agent` | str | — | Custom user agent string |
103
- | `cache` | bool | `True` | Use cache |
104
- | `cache_ttl` | int | `86400` | Cache TTL in seconds |
105
- | `response_type` | str | — | `"json"` returns metadata + base64 data URI |
106
-
107
- ### `snap.info(url)` -> `dict`
108
-
109
- Check if a screenshot is cached without capturing. Returns `{ url, cached, cache_key, cached_at, expires_at, content_type }`.
110
-
111
- ### `snap.usage()` -> `dict`
112
-
113
- Get current month's usage.
114
-
115
- ### `snap.usage_daily(days=30)` -> `dict`
116
-
117
- Get daily usage breakdown (default 30 days).
118
-
119
- ## LangChain Integration
120
-
121
- Use SnapRender as a [LangChain](https://python.langchain.com/) tool for AI agents:
122
-
123
- ```python
124
- import os
125
- from langchain_core.tools import tool
126
- from snaprender import SnapRender
127
-
128
- client = SnapRender(api_key=os.environ["SNAPRENDER_API_KEY"])
129
-
130
- @tool
131
- def take_screenshot(url: str, format: str = "png", dark_mode: bool = False) -> str:
132
- """Capture a screenshot of any website URL. Returns base64 data URI."""
133
- result = client.capture(
134
- url, format=format, dark_mode=dark_mode, response_type="json"
135
- )
136
- return result["image"]
137
- ```
138
-
139
- Works with LangGraph, CrewAI, and any framework that supports LangChain tools.
140
-
141
- ## Error Handling
142
-
143
- ```python
144
- from snaprender import SnapRender, SnapRenderError
145
-
146
- snap = SnapRender(api_key="sk_live_...")
147
-
148
- try:
149
- snap.capture("https://example.com")
150
- except SnapRenderError as e:
151
- print(e.code) # "QUOTA_EXCEEDED"
152
- print(e.status) # 429
153
- print(e) # "Monthly quota exceeded"
154
- ```
155
-
156
- ## Links
157
-
158
- - [Documentation](https://snap-render.com/docs)
159
- - [Pricing](https://snap-render.com/pricing)
160
- - [Dashboard](https://app.snap-render.com/dashboard)
161
- - [Blog](https://snap-render.com/blog)
162
- - [GitHub](https://github.com/User0856/snaprender)
163
-
164
- ## License
165
-
166
- MIT
@@ -1,152 +0,0 @@
1
- # snaprender
2
-
3
- [![PyPI version](https://img.shields.io/pypi/v/snaprender)](https://pypi.org/project/snaprender/)
4
- [![PyPI downloads](https://img.shields.io/pypi/dm/snaprender)](https://pypi.org/project/snaprender/)
5
- [![license](https://img.shields.io/pypi/l/snaprender)](https://github.com/User0856/snaprender/blob/main/LICENSE)
6
-
7
- Official Python SDK for the [SnapRender](https://snap-render.com) Screenshot API — capture pixel-perfect screenshots of any webpage with a single API call.
8
-
9
- **500 free screenshots/month — [Get your API key](https://snap-render.com/auth/signup?ref=pypi)**
10
-
11
- ## Features
12
-
13
- - **Multiple output formats** — PNG, JPEG, WebP, and PDF
14
- - **Device emulation** — iPhone, iPad, Pixel, and more presets
15
- - **Dark mode** — Capture pages with `prefers-color-scheme: dark`
16
- - **Ad blocking** — Remove ads automatically before capture
17
- - **Cookie banner removal** — Clean screenshots without consent popups
18
- - **Smart caching** — Configurable CDN cache with TTL control
19
- - **Full-page captures** — Screenshot the entire scrollable page
20
-
21
- ## Install
22
-
23
- ```bash
24
- pip install snaprender
25
- ```
26
-
27
- ## Quick Start
28
-
29
- ```python
30
- from snaprender import SnapRender
31
-
32
- snap = SnapRender(api_key="sk_live_...")
33
-
34
- # Capture a screenshot
35
- image = snap.capture("https://example.com")
36
- with open("screenshot.png", "wb") as f:
37
- f.write(image)
38
-
39
- # Capture with options
40
- jpg = snap.capture(
41
- "https://example.com",
42
- format="jpeg",
43
- width=1920,
44
- height=1080,
45
- full_page=True,
46
- dark_mode=True,
47
- quality=95,
48
- )
49
-
50
- # Check cache status
51
- info = snap.info("https://example.com")
52
- print(info["cached"]) # True/False
53
- print(info["expires_at"]) # ISO date string (when cached)
54
-
55
- # Get usage
56
- usage = snap.usage()
57
- print(f"{usage['used']}/{usage['limit']} screenshots used")
58
- ```
59
-
60
- ## Context Manager
61
-
62
- ```python
63
- with SnapRender(api_key="sk_live_...") as snap:
64
- image = snap.capture("https://example.com")
65
- ```
66
-
67
- ## API
68
-
69
- ### `SnapRender(api_key, base_url="https://app.snap-render.com", timeout=60.0)`
70
-
71
- ### `snap.capture(url, **options)` -> `bytes`
72
-
73
- | Option | Type | Default | Description |
74
- |--------|------|---------|-------------|
75
- | `url` | str | — | URL to capture (required) |
76
- | `format` | str | `"png"` | `"png"`, `"jpeg"`, `"webp"`, or `"pdf"` |
77
- | `width` | int | `1280` | Viewport width |
78
- | `height` | int | `800` | Viewport height |
79
- | `full_page` | bool | `False` | Capture full scrollable page |
80
- | `quality` | int | `90` | JPEG/WebP quality (1-100) |
81
- | `delay` | int | `0` | Wait ms after page load |
82
- | `dark_mode` | bool | `False` | Emulate dark mode |
83
- | `block_ads` | bool | `True` | Block ad networks |
84
- | `block_cookie_banners` | bool | `True` | Remove cookie banners |
85
- | `device` | str | — | Device preset (`"iphone_14"`, `"iphone_15_pro"`, `"pixel_7"`, `"ipad_pro"`, `"macbook_pro"`) |
86
- | `hide_selectors` | str | — | Comma-separated CSS selectors to hide |
87
- | `click_selector` | str | — | CSS selector to click before capture |
88
- | `user_agent` | str | — | Custom user agent string |
89
- | `cache` | bool | `True` | Use cache |
90
- | `cache_ttl` | int | `86400` | Cache TTL in seconds |
91
- | `response_type` | str | — | `"json"` returns metadata + base64 data URI |
92
-
93
- ### `snap.info(url)` -> `dict`
94
-
95
- Check if a screenshot is cached without capturing. Returns `{ url, cached, cache_key, cached_at, expires_at, content_type }`.
96
-
97
- ### `snap.usage()` -> `dict`
98
-
99
- Get current month's usage.
100
-
101
- ### `snap.usage_daily(days=30)` -> `dict`
102
-
103
- Get daily usage breakdown (default 30 days).
104
-
105
- ## LangChain Integration
106
-
107
- Use SnapRender as a [LangChain](https://python.langchain.com/) tool for AI agents:
108
-
109
- ```python
110
- import os
111
- from langchain_core.tools import tool
112
- from snaprender import SnapRender
113
-
114
- client = SnapRender(api_key=os.environ["SNAPRENDER_API_KEY"])
115
-
116
- @tool
117
- def take_screenshot(url: str, format: str = "png", dark_mode: bool = False) -> str:
118
- """Capture a screenshot of any website URL. Returns base64 data URI."""
119
- result = client.capture(
120
- url, format=format, dark_mode=dark_mode, response_type="json"
121
- )
122
- return result["image"]
123
- ```
124
-
125
- Works with LangGraph, CrewAI, and any framework that supports LangChain tools.
126
-
127
- ## Error Handling
128
-
129
- ```python
130
- from snaprender import SnapRender, SnapRenderError
131
-
132
- snap = SnapRender(api_key="sk_live_...")
133
-
134
- try:
135
- snap.capture("https://example.com")
136
- except SnapRenderError as e:
137
- print(e.code) # "QUOTA_EXCEEDED"
138
- print(e.status) # 429
139
- print(e) # "Monthly quota exceeded"
140
- ```
141
-
142
- ## Links
143
-
144
- - [Documentation](https://snap-render.com/docs)
145
- - [Pricing](https://snap-render.com/pricing)
146
- - [Dashboard](https://app.snap-render.com/dashboard)
147
- - [Blog](https://snap-render.com/blog)
148
- - [GitHub](https://github.com/User0856/snaprender)
149
-
150
- ## License
151
-
152
- MIT
File without changes
File without changes