{"id":24801361,"url":"https://github.com/urlbox/urlbox-python","last_synced_at":"2025-10-13T02:32:03.691Z","repository":{"id":45560447,"uuid":"429490284","full_name":"urlbox/urlbox-python","owner":"urlbox","description":"The Urlbox Python package provides easy access to the Urlbox API and saves you from having to do this 👇","archived":false,"fork":false,"pushed_at":"2024-10-14T09:57:54.000Z","size":143,"stargazers_count":1,"open_issues_count":3,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-09-13T18:48:35.341Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://urlbox.io/screenshot-api/python","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/urlbox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-18T15:54:33.000Z","updated_at":"2021-12-08T17:52:38.000Z","dependencies_parsed_at":"2022-09-23T05:10:16.575Z","dependency_job_id":null,"html_url":"https://github.com/urlbox/urlbox-python","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/urlbox/urlbox-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urlbox%2Furlbox-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urlbox%2Furlbox-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urlbox%2Furlbox-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urlbox%2Furlbox-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/urlbox","download_url":"https://codeload.github.com/urlbox/urlbox-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urlbox%2Furlbox-python/sbom","scorecard":{"id":912028,"data":{"date":"2025-08-11","repo":{"name":"github.com/urlbox/urlbox-python","commit":"8d4541cbe0310002b9bdb70ee8de4cb051f8815d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.2,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 1/15 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/codecov.yml:1","Warn: no topLevel permission defined: .github/workflows/linters.yml:1","Warn: no topLevel permission defined: .github/workflows/tests.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codecov.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/urlbox/urlbox-python/codecov.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codecov.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/urlbox/urlbox-python/codecov.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/codecov.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/urlbox/urlbox-python/codecov.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/linters.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/urlbox/urlbox-python/linters.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/linters.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/urlbox/urlbox-python/linters.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/urlbox/urlbox-python/tests.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/urlbox/urlbox-python/tests.yml/main?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/codecov.yml:20","Warn: pipCommand not pinned by hash: .github/workflows/linters.yml:19","Warn: pipCommand not pinned by hash: .github/workflows/linters.yml:20","Warn: pipCommand not pinned by hash: .github/workflows/linters.yml:21","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:20","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:21","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   6 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: MIT License: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":7,"reason":"3 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2023-74 / GHSA-j8r2-6x86-q33q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 28 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-24T19:33:59.791Z","repository_id":45560447,"created_at":"2025-08-24T19:33:59.791Z","updated_at":"2025-08-24T19:33:59.791Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279014020,"owners_count":26085345,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-30T04:28:22.334Z","updated_at":"2025-10-13T02:32:03.404Z","avatar_url":"https://github.com/urlbox.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"![image](https://user-images.githubusercontent.com/1453680/143582241-f44bd8c6-c242-48f4-8f9a-ed5507948588.png)\n# Urlbox Python Library\n\n[![codecov](https://codecov.io/gh/urlbox/urlbox-python/branch/main/graph/badge.svg?token=H4TE4MQJ6X)](https://codecov.io/gh/urlbox/urlbox-python)\n![Tests](https://github.com/urlbox/urlbox-python/actions/workflows/tests.yml/badge.svg)\n![Linter](https://github.com/urlbox/urlbox-python/actions/workflows/linters.yml/badge.svg)\n\nThe Urlbox Python library provides easy access to the \u003ca href=\"https://urlbox.io/\" target=\"_blank\"\u003eUrlbox website screenshot API\u003c/a\u003e from your Python application.\n\nNow there's no need to muck around with http clients, etc...\n\nJust initialise the UrlboxClient and make a screenshot of a URL in seconds.\n\n\n## Documentation\n\nSee the \u003ca href=https://urlbox.io/docs/overview target=\"_blank\"\u003eUrlbox API Docs\u003c/a\u003e.\n\n## Requirements\n\nPython 3.x\n\n## Installation\n\n```pip install urlbox```\n\n\n## Usage\n\nFirst, grab your Urlbox API key* found in your \u003ca href=\"https://urlbox.io/dashboard/api\" target=\"_blank\"\u003eUrlbox Dashboard\u003c/a\u003e, to initialise the UrlboxClient instance.\n\n*\\* and grab your API secret - if you want to make authenticated requests. Requests will be automatically authenticated when you supply YOUR_API_SECRET.\nSo you really should.*\n\n### Quick Start:  Generate a Screenshot URL\nFor use directly in HTML templates, the browser etc.\n\nIn your python_code.py:\n```python\nfrom urlbox import UrlboxClient\n\n# Initialise the UrlboxClient (YOUR_API_SECRET is optional but recommended)\nurlbox_client = UrlboxClient(api_key=\"YOUR_API_KEY\", api_secret=\"YOUR_API_SECRET\")\n\nscreenshot_url = urlbox_client.generate_url({\"url\": \"http://example.com/\"})\n```\n\nIn your html template:\n```html\n\u003cimg src=\"{{  screenshot_url }}\"/\u003e\n```\n\n###  Quick Start: Quickly Get a Screenshot of a URL\n\n```python\nfrom urlbox import UrlboxClient\n\n# Initialise the UrlboxClient (YOUR_API_SECRET is optional but recommended)\nurlbox_client = UrlboxClient(api_key=\"YOUR_API_KEY\", api_secret=\"YOUR_API_SECRET\")\n\n# Make a request to the UrlBox API\nresponse = urlbox_client.get({\"url\": \"http://example.com/\"})\n\nresponse.content # Your screenshot 🎉 as binary image data\n\n# save screenshot image to screenshot.png:\nwith open(\"screenshot.png\", \"wb\") as f:\n    f.write(response.content)\n\n```\n\nAll UrlboxClient methods require at least one argument: a dictionary that *must include either a \"url\", or \"html\" entry*, which the Urlbox API will render as a screenshot.\n\nAdditional options in the dictionary include:\n\n\"format\" can be either: png, jpg or jpeg, avif, webp ,pdf, svg, html  *(defaults to png if not provided).*\n\n\"full_page\", \"width\", and many more.\nSee all available options here: https://urlbox.io/docs/options\n\neg:\n```python\n{\"url\": \"http://example.com/\", \"full_page\": True, \"width\": 300}\n```\n\n\n### A More Extensive Get Request\n```python\nfrom urlbox import UrlboxClient\n\nurlbox_client = UrlboxClient(api_key=\"YOUR_API_KEY\", api_secret=\"YOUR_API_SECRET\")\n\noptions = {\n\t\"url\": \"https://www.independent.co.uk/arts-entertainment/tv/news/squid-game-real-youtube-mrbeast-b1964007.html\",\n\t\"format\": \"jpg\",\n\t\"full_page\": False,\n\t\"hide_cookie_banners\": True,\n\t\"block_ads\": True\n}\n\nresponse = urlbox_client.get(options)\n\n# The Urlbox API will return binary data as the response with the\n# Content-Type header set to the relevant mime-type for the format requested.\n# For example, if you requested jpg format, the Content-Type will be image/jpeg\n# and response body will be the actual jpg binary data.\n\nresponse.content # Your screenshot. Which looks like 👇\n```\n![image](https://user-images.githubusercontent.com/1453680/143479491-78d8edbc-dfdc-48e3-9ae0-3b59bcf98e2c.png)\n\n\n## Other Methods/Requests\nThe UrlboxClient has the following public methods:\n\n### get(options)\n*(as detailed in the above examples)*\nMakes a GET request to the Urlbox API to create a screenshot for the url or html passed in the options dictionary.\n\nExample request:\n```python\nresponse = urlbox_client.get({\"url\": \"http://example.com/\"})\nresponse.content # Your screenshot 🎉\n```\n\n### delete(options)\nRemoves a previously created screenshot from the cache.\n\nExample request:\n```python\nurlbox_client.delete({\"url\": \"http://example.com/\"})\n```\n### head(options)\nIf you just want to get the response status/headers without pulling down the full response body.\n\nExample request:\n```python\nresponse = urlbox_client.head({\"url\": \"http://example.com/\"})\n\nprint(str(response.headers))\n\n```\n\nExample response headers:\n\n```json\n{\n   \"Date\":\"Fri, 26 Nov 2021 16:22:56 GMT\",\n   \"Content-Type\":\"image/png\",\n   \"Content-Length\":\"1268491\",\n   \"Connection\":\"keep-alive\",\n   \"Cache-Control\":\"public, max-age=2592000\",\n   \"Expires\":\"Sun, 26 Dec 2021 16:16:09 GMT\",\n   \"Last-Modified\":\"Fri, 26 Nov 2021 16:14:56 GMT\",\n   \"X-Renders-Used\":\"60\",\n   \"X-Renders-Reset\":\"Sun Dec 05 2021 09:58:00 GMT+0000 (Coordinated Universal Time)\",\n   \"X-Renders-Allowed\":\"22000\"\n}\n```\nYou can use these headers to check how many renders you have used or your current rate limiting status, etc.\n\n### post(options)\nUses Urlbox's webhook functionality to initialise a render of a screenshot. You will need to provide a *\"webhook_url\"* entry in the options which Urlbox will post back to when the rendering of the screenshot is complete.\n\nExample request:\n```python\nurlbox_client.post({\"url\": \"http://twitter.com/\", \"webhook_url\": \"http://yoursite.com/webhook\"})\n```\nGive it a couple of seconds, and you should receive, posted to the webhook_url specified in your request above, a post request with a JSON body similar to:\n```json\n{\n  \"event\": \"render.succeeded\",\n  \"renderId\": \"2cf5ffe2-7736-4d41-8c30-f13e16d35248\",\n  \"result\": {\n    \"renderUrl\": \"https://renders.urlbox.io/urlbox1/renders/61431b47b8538a00086c29dd/2021/11/25/e2dcec18-8353-435c-ba17-b549c849eec5.png\"\n  },\n  \"meta\": {\n    \"startTime\": \"2021-11-25T16:32:32.453Z\",\n    \"endTime\": \"2021-11-25T16:32:38.719Z\"\n  }\n}\n```\nYou can then parse the renderUrl value to access the your screenshot.\n\n\n## Secure Webhook Posts\nThe Urlbox API post to your webhook endpoint will include a header that you can use to  ensure this is a genuine request from the Urlbox API, and not a malicious actor.\n\nUsing your http client of choice, access the *x-urlbox-signature* header. Its value will be something similar to:\n\n`t=1637857959,sha256=1d721f99aa03122d494f8b49f201fdf806efaec609c614f0a0ec7b394f1d403a`\n\nUse the *webhook_validator* helper function that is included, for no extra charge, in the urlbox package to verify that the webhook post is indeed a genuine request from the Urlbox API. Like so:\n\n```python\nfrom urlbox import webhook_validator\n\n# extracted from the x-urlbox-signature header\nheader_signature = \"t=1637857959,sha256=1d721f...\"\n\n# the raw JSON payload from the webhook request body\npayload = {\n\t\"event\": \"render.succeeded\",\n\t\"renderId\": \"794383cd-b09e-4aef-a12b-fadf8aad9d63\",\n\t\"result\": {\n\t\t\"renderUrl\": \"https://renders.urlbox.io/urlbox1/renders/foo.png\"\n\t},\n\t\"meta\": {\n\t\t\"startTime\": \"2021-11-24T16:49:48.307Z\",\n\t\t\"endTime\": \"2021-11-24T16:49:53.659Z\",\n\t},\n}\n\n# Your webhook secret - coming soon.\n# NB: This is NOT your api_secret, that's different.\nwebhook_secret = \"YOUR_WEBHOOK_SECRET\"\n\n# This will either return true (if the signature is genuinely from Urlbox)\n#   or it will raise a InvalidHeaderSignatureError (if the signature is not from Urlbox)\nwebhook_validator.call(header_signature, payload, webhook_secret)\n```\n\n\n## Feedback\n\n\nFeel free to contact us if you spot a bug or have any suggestions at: support`[at]`urlbox.io.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furlbox%2Furlbox-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Furlbox%2Furlbox-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furlbox%2Furlbox-python/lists"}