{"id":24540523,"url":"https://github.com/urlbox/urlbox-dotnet","last_synced_at":"2026-04-12T09:41:41.276Z","repository":{"id":258234305,"uuid":"872513739","full_name":"urlbox/urlbox-dotnet","owner":"urlbox","description":"Capture full page website screenshots, pdf's and more with Urlbox.com's dotnet SDK","archived":false,"fork":false,"pushed_at":"2025-02-12T10:54:46.000Z","size":9366,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-22T05:37:07.204Z","etag":null,"topics":["api-client","csharp","dotnet","fullpage-screenshot","html-to-markdown","html-to-pdf","playwright","puppeteer","puppeteer-screenshot","screenshot","screenshot-api","url-screenshot","url-to-image","url-to-pdf","url-to-screenshot","website-screenshot","website-thumbnail"],"latest_commit_sha":null,"homepage":"https://urlbox.com/screenshot-api","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/urlbox.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-10-14T15:08:13.000Z","updated_at":"2025-01-22T10:10:23.000Z","dependencies_parsed_at":"2024-12-20T10:38:01.404Z","dependency_job_id":"791e6909-94de-4cc4-906b-a47d5688213b","html_url":"https://github.com/urlbox/urlbox-dotnet","commit_stats":null,"previous_names":["urlbox/urlbox-dotnet"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/urlbox/urlbox-dotnet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urlbox%2Furlbox-dotnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urlbox%2Furlbox-dotnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urlbox%2Furlbox-dotnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urlbox%2Furlbox-dotnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/urlbox","download_url":"https://codeload.github.com/urlbox/urlbox-dotnet/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urlbox%2Furlbox-dotnet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273220496,"owners_count":25066396,"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-09-02T02:00:09.530Z","response_time":77,"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":["api-client","csharp","dotnet","fullpage-screenshot","html-to-markdown","html-to-pdf","playwright","puppeteer","puppeteer-screenshot","screenshot","screenshot-api","url-screenshot","url-to-image","url-to-pdf","url-to-screenshot","website-screenshot","website-thumbnail"],"created_at":"2025-01-22T18:13:55.337Z","updated_at":"2026-04-12T09:41:36.247Z","avatar_url":"https://github.com/urlbox.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![image](Images/urlbox-graphic.jpg)](https://www.urlbox.com)\n\n***\n\n# The Urlbox .NET SDK\n\nThe Urlbox .NET SDK provides easy access to the [Urlbox API](https://urlbox.com/) from your application.\n\nJust initialise Urlbox and generate a screenshot of a URL or HTML in no time.\n\nCheck out our [blog](https://urlbox.com/blog) for more insights on everything screenshots and what we're doing.\n\n\u003e **Note:** At Urlbox we make `Renders`. Typically, when we refer to a render here or anywhere else, we are referring to the entire process as a whole of taking your options, performing our magic, and sending back a screenshot your way.\n\n#### Checkout [OneMillionScreenshots](https://onemillionscreenshots.com/) - A site that uses Urlbox to show over 1 million of the web's homepages!\n***\n\n# Table Of Contents\n \n\u003c!-- TOC --\u003e\n* [Documentation](#documentation)\n* [Requirements](#requirements)\n* [Installation](#installation)\n* [Usage](#usage)\n  * [Start here](#start-here)\n  * [Getting Started - `TakeScreenshot()`](#getting-started---takescreenshot)\n  * [Configuring Options](#configuring-options-)\n    * [Using the options builder](#using-the-options-builder)\n    * [Using the `new` keyword, setting during initialization](#using-the-new-keyword-setting-during-initialization)\n    * [What to do if an option isn't available in the builder](#what-to-do-if-an-option-isnt-available-in-the-builder)\n  * [Render Links - `GenerateRenderLink()`](#render-links---generaterenderlink)\n  * [Sync Requests - `Render()`](#sync-requests---render)\n  * [Async Requests - `RenderAsync()`](#async-requests---renderasync)\n    * [Polling](#polling)\n    * [Webhooks](#webhooks)\n  * [Handling Errors](#handling-errors)\n  * [Dependency Injection](#dependency-injection)\n* [Utility Functions](#utility-functions)\n    * [`TakeScreenshot(options)`](#takescreenshotoptions)\n    * [`TakePdf(options)`](#takepdfoptions)\n    * [`TakeMp4(options)`](#takemp4options)\n    * [`TakeScreenshotWithMetadata(options)`](#takescreenshotwithmetadataoptions)\n    * [`ExtractMetadata(options)`](#extractmetadataoptions)\n    * [`ExtractMarkdown(options)`](#extractmarkdownoptions)\n    * [`ExtractHtml(options)`](#extracthtmloptions)\n    * [`ExtractMhtml(options)`](#extractmhtmloptions)\n    * [`DownloadAsBase64(options)`](#downloadasbase64options-)\n    * [`DownloadToFile(options, filePath)`](#downloadtofileoptions-filepath-)\n    * [`GeneratePNGUrl(options)`](#generatepngurloptions-)\n    * [`GenerateJPEGUrl(options)`](#generatejpegurloptions-)\n    * [`GeneratePDFUrl(options)`](#generatepdfurloptions-)\n* [Popular Use Cases](#popular-use-cases)\n  * [Taking a Full Page Screenshot](#taking-a-full-page-screenshot)\n    * [Example MP4 (Full Page)](#example-mp4--full-page-)\n  * [Taking a Mobile view screenshot](#taking-a-mobile-view-screenshot)\n  * [Failing a request on 4XX-5XX](#failing-a-request-on-4xx-5xx)\n  * [Extracting Markdown/Metadata/HTML](#extracting-markdownmetadatahtml)\n  * [Generating a Screenshot Using a Selector](#generating-a-screenshot-using-a-selector)\n  * [Uploading to the cloud via an S3 bucket](#uploading-to-the-cloud-via-an-s3-bucket)\n  * [Using a Proxy](#using-a-proxy)\n  * [Using Webhooks](#using-webhooks)\n    * [1. Visit your Urlbox dashboard, and get your Webhook Secret.](#1-visit-your-urlbox-dashboard-and-get-your-webhook-secret)\n    * [2. Create your Urlbox instance in your C# project:](#2-create-your-urlbox-instance-in-your-c-project)\n    * [3. Make a request through any of our rendering methods.](#3-make-a-request-through-any-of-our-rendering-methods-)\n    * [4. Verify that the webhook comes from Urlbox](#4-verify-that-the-webhook-comes-from-urlbox)\n* [API Reference](#api-reference)\n  * [Urlbox API Reference](#urlbox-api-reference)\n    * [Constructor](#constructor)\n    * [Static Methods](#static-methods)\n    * [Screenshot and File Generation Methods](#screenshot-and-file-generation-methods)\n    * [Download and File Handling Methods](#download-and-file-handling-methods)\n    * [URL Generation Methods](#url-generation-methods)\n    * [Status and Validation Methods](#status-and-validation-methods)\n    * [Response Classes](#response-classes)\n      * [`SyncUrlboxResponse`](#syncurlboxresponse)\n      * [`AsyncUrlboxResponse`](#asyncurlboxresponse)\n      * [`WebhookUrlboxResponse`](#webhookurlboxresponse)\n      * [`UrlboxException`](#urlboxexception)\n      * [`UrlboxMetadata`](#urlboxmetadata)\n    * [Available Enums](#available-enums)\n  * [Examples](#examples)\n    * [Example HTML](#example-html)\n    * [Example PDF](#example-pdf)\n    * [Example PDF Highlighting](#example-pdf-highlighting)\n    * [Example PNG injecting Javascript](#example-png-injecting-javascript)\n  * [Feedback](#feedback)\n  * [Changelog](#changelog)\n\u003c!-- TOC --\u003e\n\n***\n\n# Documentation\n\nSee [here](https://urlbox.com/docs/overview) for the Urlbox API Docs. It includes an exhaustive list of all the options you could pass to our API, including what they do and example usage.\n\nWe also have guides for how to set up uploading your final render to your own [S3](https://urlbox.com/docs/guides/s3) bucket, or use [proxies](https://urlbox.com/docs/guides/proxies) for geo-specific sites.\n\n# Requirements\n\nTo use this SDK, you need .NET Core 6.0 or later.\n\n# Installation\n\nNuget:\n\n```bash\ndotnet add package urlbox.sdk.dotnet\n```\n\n# Usage\n\n## Start here\n\nVisit [Urlbox](https://urlbox.com) to sign up for a trial. You'll need to visit your [projects](https://urlbox.com/dashboard/projects) page, and gather your Publishable Key, Secret Key, and Webhook Secret key (if you intend on using webhooks).\n\nWith a new account you'll only have one project, so visit the project configuration page for it, where you should see something like this:\n\n![The project settings page](Images/projectKeys.png)\n\n## Getting Started - `TakeScreenshot()`\n\nIf you want something super simple, initialize an instance of Urlbox with the above credentials, then call our `TakeScreenshot(options)` method with the options of your choosing:\n\n```CS\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing UrlboxSDK; // This is our package\n\nnamespace MyNamespace\n{\n    class Program\n    {\n        static async Task Main()\n        {\n            // We highly recommend storing your Urlbox API key and secret somewhere secure.\n            string apiKey = Environment.GetEnvironmentVariable(\"URLBOX_API_KEY\");\n            string apiSecret = Environment.GetEnvironmentVariable(\"URLBOX_API_SECRET\");\n            string webhookSecret = Environment.GetEnvironmentVariable(\"URLBOX_WEBHOOK_SECRET\");\n\n            // Create an instance of Urlbox and the Urlbox options you'd like to use\n            Urlbox urlbox = Urlbox.FromCredentials(apiKey, apiSecret, webhookSecret);\n            // Use the builder pattern for fluent options\n            UrlboxOptions options = Urlbox.Options(url: \"https://urlbox.com\").Build();\n          \n            // Take a screenshot - The default format is PNG\n            AsyncUrlboxResponse response = await urlbox.TakeScreenshot(options);\n            \n            // This is the URL destination where you can find your finalized render.\n            Console.Writeline(response.RenderUrl); \n        }\n    }\n}\n```\n\nIf you use the above with your own keys, it will give you back an object with a `renderUrl`. Making a GET request to that renderUrl will give you back a PNG back like this:\n\n![](../Images/urlbox-png.png)\n\n***\n\n## Configuring Options \n\nPassing options are where the magic comes in. Options are simply extra inputs that we use to adapt the way we take the screenshot, or adapt any of the other steps involved in the rendering process.\n\n\u003e**Note:** Almost all of our options are optional. However, you must at least provide a URL or some HTML in your options in order for us to know what we are rendering for you.\n\nYou could, for example, change the way the request is made to your desired URL (like using a proxy server, passing in extra headers, an authorization token or some cookies), or change the way the page looks (like injecting Javascript, highlighting words, or making the background a tasteful fuchsia pink). \n\nThere are a few ways to retrieve a screenshot from Urlbox, depending on how and when you need it. You could retrieve it as a [raw file](https://urlbox.com/docs/options#response_type) (using `UrlboxOptions.ResponseType(ResponseType.Binary)` ), or by default, as a JSON object with its size and stored location. \n\nThere are a plethora of other options you can use. Checkout the [docs](https://urlbox.com/docs/overview) for more information.\n\nTo initialise your urlbox options, we advise using the option builder. Start by calling the static method `Urlbox.Options()` with the URL or HTML you want to screenshot.\n\nThe builder will validate your options on `.Build()`, and allow for a more readable/fluent interface in your code.\n\n### Using the options builder\n```CS\nusing UrlboxSDK;\nusing UrlboxSDK.Options.Resource;\nusing UrlboxSDK.Response.Resource;\n\nUrlbox urlbox = Urlbox.FromCredentials(\"YOUR_KEY\", \"YOUR_SECRET\", \"YOUR_WEBHOOK_SECRET\");\n\nUrlboxOptions options = Urlbox.Options(\n                    url: \"https://urlbox.com\"\n                )\n                // Any Bool option sets to true when called with no arguments\n                .FullPage()\n                .Cookie(\"some=cookie\", \"someother=cookie\")\n                .Gpu()\n                // Enumerables can be accessed/imported by their name:\n                .ResponseType(ResponseType.Json)\n                .BlockAds()\n                .HideCookieBanners()\n                .BlockUrls(\"https://ads.com\", \"https://trackers.com\")\n                .Build();\n\nAsyncUrlboxResponse response = await urlbox.TakeScreenshot(options);\n\nConsole.WriteLine(response.Status);\nConsole.WriteLine(response.RenderUrl);\n```\n\nYou can alternatively set the Urlbox options with the `new` keyword.\n\n### Using the `new` keyword, setting during initialization\n\nWe advise against using the `new` keyword. If you would like to anyway, here's an example:\n\n```CS\nUrlboxOptions options = new(url: \"https://urlbox.com\")\n{\n    Format = Format.Pdf,\n    Gpu = true,\n    Retina = true,\n    DarkMode = true\n};\n\n// Or set them after init:\noptions.FullPage = true;\n\nAsyncUrlboxResponse response = await urlbox.TakeScreenshot(options);\n```\n\n### What to do if an option isn't available in the builder\n\nOur [latest](https://urlbox.com/docs/options#engine_version) engine is updated regularly, including new options which are released to better help you render screenshots.\n\nIf you can't find an option within the builder, because our SDK isn't yet in sync with any latest changes, please do use our overloads for `render` and `renderAsync` which take an `IDictionary\u003cstring, object\u003e` instead of a `UrlboxOptions` type.\n\nHere's an example:\n\n```CS\nIDictionary\u003cstring, object\u003e options = new Dictionary\u003cstring, object\u003e\n    {\n        { \"click_accept\", true },\n        { \"url\", \"https://urlbox.com\" }\n        { \"theOption\", \"YouCouldntFind\" }\n    };\nSyncUrlboxResponse response = await urlbox.Render(options);\n\nConsole.WriteLine(response);\n```\nPlease Bear in mind that this won't have the benefit of pre-validation.\n\n***\n\n## Render Links - `GenerateRenderLink()`\n\nWith Urlbox you can get a screenshot in a number of ways. It may seem a little complex at first, but each method has its purpose.\n\nTake a look at the [section in our docs](https://urlbox.com/docs/api/rest-api-vs-render-links#render-links) which explains the main benefits of using a render link over our `/sync` and `/async` methods.\n\nTo get a render link, run the `GenerateRenderLink(options)` with your options.\n\nOnce you have that render link, you're free to embed it anywhere you please. Make a GET request to that render link, and it will synchronously run a render, and return a screenshot. This is particularly handy for embedding into an `\u003cimg\u003e` tag.\n\nThe method will, by default, sign the render link, for enhanced security. You can opt out of this by passing `urlbox.GenerateRenderLink(options, sign: false);`\n\nHere's an example:\n\n```CS\nUrlbox urlbox = Urlbox.FromCredentials(\"YOUR_KEY\", \"YOUR_SECRET\", \"YOUR_WEBHOOK_SECRET\");\n\nUrlboxOptions options = Urlbox.Options(\n                    url: \"https://bbc.com\"\n                )\n                .Format(Format.Pdf)\n                .Build();\n\nstring renderLink = urlbox.GenerateRenderLink(options, sign: true);\n\nConsole.WriteLine(renderLink);\n```\n\n## Sync Requests - `Render()`\n\nWe have 2 other ways to get a screenshot from Urlbox, `render/sync` and `render/async`.\n\nMaking a request to the [`/sync`](https://urlbox.com/docs/api#create-a-render-synchronously) endpoint means making a request that waits for your screenshot to be taken, and only then returns the response with your finished screenshot. You can achieve this by using the main `Render(options)` method.\n\nHere is an example:\n\n```CS\nUrlbox urlbox = Urlbox.FromCredentials(\"YOUR_KEY\", \"YOUR_SECRET\", \"YOUR_WEBHOOK_SECRET\");\n\nUrlboxOptions options = Urlbox.Options(\n                    url: \"https://youtube.com\"\n                )\n                .Format(Format.Pdf)\n                .Build();\n\nSyncUrlboxResponse response = await urlbox.Render(options);\n```\n\nIf you haven't explicitly asked for a binary response in your options, you'll get a JSON 200 response like this:\n\n```JSON\n{\n    # Where the final screenshot is stored -- If you setup S3, it will be your bucket name / cdn host in the URL.\n    \"renderUrl\": \"https://renders.urlbox.com/ub-temp-renders/renders/662facc1f3b58e0a6df7a98b/2024/10/23/1b4df8c9-f347-4661-9b6a-1c969beb7522.mp4\",\n    # The size of the file in bytes\n    \"size\": 272154\n}\n```\n\nIf you find that the kind of screenshot you are taking requires some time, and you don't want your network connection to be open for that long, the `/async` method may be better suited to your needs. Our `TakeScreenshot()` method already implements a polling mechanism using the `/async` endpoint and status checks, so you don't have to set one up yourself!\n\n***\n\n## Async Requests - `RenderAsync()`\n\nSome renders can take some time to complete (think full page screenshots of infinitely scrolling sites, MP4 with retina level quality, or large full page PDF renders).\n\nIf you anticipate your request being larger, then we would recommend using the [`/async`](https://urlbox.com/docs/api#create-a-render-asynchronously) endpoint by calling the `RenderAsync(options)` method or `TakeScreenshot(options)`.\n\nHere is an example of its usage:\n\n```CS\nUrlbox urlbox = Urlbox.FromCredentials(\"YOUR_KEY\", \"YOUR_SECRET\", \"YOUR_WEBHOOK_SECRET\");\n\nUrlboxOptions options = Urlbox.Options(\n                    url: \"https://google.com\"\n                )\n                .Format(Format.Pdf)\n                .Build();\n\nAsyncUrlboxResponse = await urlbox.RenderAsync(options);\n```\n\nThis returns you:\n\n```JSON\n{\n    # When this is \"succeeded\", your render will be ready\n    \"status\": \"created\",\n    # This is your unique render id\n    \"renderId\": \"fe7af5df-80e7-4b38-973a-005ebf06dabb\", \n    # Make a GET to this to find out if your render is ready\n    \"statusUrl\": \"https://api.urlbox.com/v1/render/fe7af5df-80e7-4b38-973a-005ebf06dabb\"\n}\n```\n\nYou can find out _when_ your async render has been successfully made in two ways:\n\n### Polling\n\nYou can [poll](https://en.wikipedia.org/wiki/Polling_(computer_science)) the `statusUrl` endpoint that comes back from the `/async` response via a GET request. The response from that status URL will include `\"status\": \"succeeded\"` when finished, as well as your final render URL.\n\nUse `TakeScreenshot()` to use our `/async` endpoint with a pre-built polling mechanism. The method will try for 60 seconds by default with an optional timeout.\n\n### Webhooks\n\nYou can also use [webhooks](https://urlbox.com/docs/webhooks#using-webhooks) to tell you when your render is ready. Make a request to Urlbox, and we send the response as a POST request to an endpoint of your choosing.\n\nSee the [Using Webhooks](#using-webhooks) section of these docs in for how to use webhooks with Urlbox in your application.\n\n## Handling Errors\n\nThe SDK deserializes our API errors for you into an Exception class.\n\nThe UrlboxException gives you some useful data. Here's an example:\n\n```CS\nUrlbox urlbox = new(apiKey, apiSecret);\n\nUrlboxOptions options = Urlbox.Options(\n        url: \"https://notaresolvableurlbox.com\"\n    )\n    .Build();\n\ntry\n{\n    AsyncUrlboxResponse response = await urlbox.TakeScreenshot(options);\n}\ncatch (UrlboxException exception)\n{\n    Console.WriteLine(exception.Message); // EG Invalid options, please check errors\n    Console.WriteLine(exception.Code); // EG InvalidOptions\n    Console.WriteLine(exception.Errors); // EG {\"url\":[\"error resolving URL - ENOTFOUND notresolvableurlbox.com\"]}\n    Console.WriteLine(exception.RequestId); // EG 06u6e285-ahd3-45vc-ac8c-36b95e6c15b5 \n}\n```\n\nThe `Code` property will typically result in one of [these](https://urlbox.com/docs/api#error-codes). We're adding to this consistently to make you're error handling experience more streamlined.\n\nGot an unexpected 4XX or 5XX? You can ensure renders fail and don't count toward your render count for [non-2XX responses](#failing-a-request-on-4xx-5xx).\n\n## Dependency Injection\n\nWe've set up an extension for DI. When you're configuring your DI you can run `services.AddUrlbox()` to define the Urlbox instance once. Here's a simple ASP.net app:\n\n```CS\nusing UrlboxSDK.DI.Extension;\nusing UrlboxSDK;\nusing UrlboxSDK.Response.Resource;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Add The Urlbox service to the service container\nbuilder.Services.AddUrlbox(options =\u003e\n{\n    options.Key = \"YOUR_API_KEY\";\n    options.Secret = \"YOUR_SECRET\";\n    options.WebhookSecret = \"YOUR-WEBHOOK-SECRET\"; // Optional\n    options.BaseUrl = \"https://api-eu.urlbox.com\";    // Optional\n});\n\nvar app = builder.Build();\n\napp.UseHttpsRedirection();\n\n// Urlbox gets injected from service container by reference to its interface\napp.MapGet(\"/screenshot\", async (HttpContext context, IUrlbox urlbox) =\u003e\n{\n    var options = Urlbox.Options(url: \"https://example.com\").Build();\n    try\n    {\n        AsyncUrlboxResponse response = await urlbox.TakeScreenshot(options);\n        return Results.Json(new { message = \"Screenshot generated!\", response });\n    }\n    catch (Exception ex)\n    {\n        return Results.Json(new { message = \"Failed to generate screenshot\", error = ex.Message });\n    }\n});\n\napp.Run();\n```\n\n***\n\n# Utility Functions\n\nTo make capturing and rendering screenshots even simpler, we’ve created several methods for common scenarios. Use these methods to quickly generate specific types of screenshots or files based on your needs:\n\n### `TakeScreenshot(options)`\nOur simplest method to take a screenshot. Uses the `/async` Urlbox endpoint, and polls until the render is ready to reduce the time network requests stay open.\n\n### `TakePdf(options)`\nConvert any URL or HTML into a PDF.\n\n### `TakeMp4(options)`\nTurn any URL or HTML into an MP4 video. For a scrolling effect over the entire page, set `FullPage = true` to capture the full length of the content.\n\n### `TakeScreenshotWithMetadata(options)`\nTakes a screenshot of any URL or HTML, bringing back a [UrlboxMetadata](#urlboxmetadata) object too with more information about the site.\n\n### `ExtractMetadata(options)`\nTakes a screenshot of any URL or HTML, but extracts only the metadata from the render. Useful when you only need the `UrlboxMetadata` object from the render.\n\n### `ExtractMarkdown(options)`\nTakes a screenshot of any URL or HTML, downloads it and gives back the extracted markdown file as a string.\n\n### `ExtractHtml(options)`\nTakes a screenshot of any URL or HTML, downloads it and gives back the extracted HTML file as a string.\n\n### `ExtractMhtml(options)`\nTakes a screenshot of any URL or HTML, downloads it and gives back the extracted MHTML file as a string.\n\n### `DownloadAsBase64(options)` \nGets a render link, runs a GET to that link to render your screenshot, then downloads the screenshot file as a Base64 string.\n\n### `DownloadToFile(options, filePath)` \nGets a render link, runs a GET to that link to render your screenshot, then downloads and stores the screenshot to the given filePath.\n\n### `GeneratePNGUrl(options)` \nGets a render link for a screenshot in PNG format.\n\n### `GenerateJPEGUrl(options)` \nGets a render link for a screenshot in JPEG format.\n\n### `GeneratePDFUrl(options)` \nGets a render link for a screenshot in PDF format.\n\n# Popular Use Cases\n\n## Taking a Full Page Screenshot\n\nWant to take a screenshot of the full page from top to bottom?\n\nFor almost all formats, this is available by simply running a request with the full page option\n\n```CS\nUrlboxOptions options = Urlbox.Options(url: \"https://google.com\")\n  .FullPage()\n  .Build();\n\nSyncUrlboxResponse response = await urlbox.Render(options);\n```\n\nThis will generate you a tall render, from the top to the bottom of the page.\n\nFor video renders, there a bit more to it. To simply take a video of the website scrolling from top to bottom run a request like this:\n\n```CS\nUrlboxOptions options = Urlbox.Options(url: \"https://urlbox.com\")\n        .Format(Format.Mp4)\n        .FullPage()\n        .VideoScroll()\n        .Build();\n\nSyncUrlboxResponse response = await urlbox.Render(options);\n```\nThis will render you a full page MP4 as the example below shows:\n\n### [Example MP4 (Full Page)](../Examples/mp4.mp4)\n\n## Taking a Mobile view screenshot\n\nYou may want to take a screenshot of a website/HTML as though it were being accessed from a mobile device.\n\nTo achieve this you can simply change the width of the viewport to suit your needs. Here's an example for mobile:\n\n```CS\nUrlboxOptions options = Urlbox.Options(url: \"https://urlbox.com\")\n  .Width(375)\n  .Build();\n\nSyncUrlboxResponse response = await urlbox.Render(options);\n```\n\nWhich should render you something like the below example:\n\n![](/Examples/mobile.png)\n\n## Failing a request on 4XX-5XX\n\nBy default, Urlbox treats HTTP responses with status codes in the 400-599 range as successful renders, counting them toward your total render count.\n\nThis feature enables you to capture screenshots of error responses when needed. If you prefer your render requests to fail when the response falls within this range, you can configure this behavior by passing `FailOn4xx()` and/or `FailOn5xx` as such:\n\n```CS\nUrlboxOptions options = Urlbox.Options(url: \"https://google.com\")\n  .FailOn4xx()\n  .FailOn5xx()\n  .Build();\n\nSyncUrlboxResponse response = await urlbox.Render(options);\n```\n\nThis can save you renders over the month, particularly when tackling websites like tricky social media pages.\n\nIf there is a failure, it will give you back a [UrlboxException](#urlboxexception). \n\n## Extracting Markdown/Metadata/HTML\n\nIn addition to your main render format for your URL/HTML, you can additionally render and save the same screenshot as HTML, Markdown and/or Metadata in the same request.\n\n```CS\nUrlbox urlbox = Urlbox.FromCredentials(\"YOUR_KEY\", \"YOUR_SECRET\", \"YOUR_WEBHOOK_SECRET\");\n\nUrlboxOptions options = Urlbox.Options(\n                    url: \"https://urlbox.com\"\n                )\n                .Format(Format.Pdf)\n                .SaveMarkdown() // This saves the same URL/HTML's content as a markdown file\n                .SaveHtml() // This saves the same URL/HTML's content as its HTML\n                .SaveMetadata() // This extracts the metadata, saves it and sends it back in the response.\n                .Metadata() // This extracts the metadata from the URL/HTML, and sends it back in the response without saving it to the cloud.\n                .Build();\n\nSyncUrlboxResponse response = await urlbox.Render(options);\n```\n\nThe JSON response is deserialized and turned into the SyncUrlboxResponse. The JSON response would look like this:\n\n```JSON\n{\n  \"renderUrl\": \"https://renders.urlbox.com/ub-temp-renders/renders/662facc1f3b58e0a6df7a98b/2024/10/23/1b4df8c9-f347-4661-9b6a-1c969beb7522.pdf\",\n  \"size\": 1048576,\n  \"htmlUrl\": \"https://renders.urlbox.com/ub-temp-renders/renders/662facc1f3b58e0a6df7a98b/2024/10/23/1b4df8c9-f347-4661-9b6a-1c969beb7522.html\",\n  \"metadataUrl\": \"https://renders.urlbox.com/ub-temp-renders/renders/662facc1f3b58e0a6df7a98b/2024/10/23/1b4df8c9-f347-4661-9b6a-1c969beb7522.json\",\n  \"markdownUrl\": \"https://renders.urlbox.com/ub-temp-renders/renders/662facc1f3b58e0a6df7a98b/2024/10/23/1b4df8c9-f347-4661-9b6a-1c969beb7522.md\",\n  \"metadata\": {\n    \"title\": \"Example Page\",\n    \"description\": \"This is an example of metadata information.\",\n    \"screenshot_date\": \"2024-11-06T12:34:56Z\",\n    \"file_size\": 1048576,\n    \"mime_type\": \"application/pdf\"\n  }\n}\n```\n\nWhen using the screenshot and file generation methods from our SDK like `TakeScreenshot()`, `Render()` or `RenderAsync()`, responses will all be turned into a readable class instance for you, being either the `SyncUrlboxResponse` or `AsyncUrlboxResponse` for 200's.\n\nWhen downloading metadata, you can opt to either save the metadata, or just return it in the JSON response as above. Our helper method `TakeScreenshotWithMetadata()` will not store the metadata so not produce a URL. It will instead only return the metadata object as above.\n\n## Generating a Screenshot Using a Selector\n\nThere are times when you don't want to screenshot the entirety of a website. You may want to avoid manual cropping after taking your screenshot. You can take a screenshot of only the elements that you wish to using the selector.\n\nHere's an example of using the selector option with our `Render(options)` method:\n\n```CS\nUrlbox urlbox = Urlbox.FromCredentials(\"YOUR_KEY\", \"YOUR_SECRET\", \"YOUR_WEBHOOK_SECRET\");\n\nUrlboxOptions options = Urlbox.Options(url: \"https://github.com\")\n    .Selector(\".octicon-mark-github\")\n    .Build();\n\nSyncUrlboxResponse response = await urlbox.Render(options);\n```\n\nThis will take the ID selector \".octicon-mark-github\", and return a screenshot that looks like this:\n\n![](../Images/gh.png)\n\n## Uploading to the cloud via an S3 bucket\n\nFor a typical render, we do the storing for you. You can opt to save the final screenshot to your own cloud provider.\n\nWe would _**highly**_ recommend you follow our S3 setup instructions. Setting up a cloud bucket can be tedious at the best of times, so [this](https://urlbox.com/docs/storage/configure-s3) part of our docs can help untangle the process.\n\nIn theory, we support any S3 compatible provider, though we have tested the following providers:\n\n- BackBlaze B2\n- AWS S3\n- Cloudflare R2\n- Google Cloud Storage\n- Digital Ocean Spaces\n\nIf there's another cloud provider you would like to use, please try to reach out to us if you're struggling to get setup.\n\nWe allow for public CDN hosts, private buckets and buckets with object locking enabled.\n\nOnce you've set up your bucket, you can simply add `UrlboxOptions.UseS3()` to your options before making your request.\n\n```CS\nUrlbox urlbox = Urlbox.FromCredentials(\"YOUR_KEY\", \"YOUR_SECRET\", \"YOUR_WEBHOOK_SECRET\");\n\nUrlboxOptions options = Urlbox.Options(url: \"https://google.com\")\n    .UseS3()\n    .Build();\n\nSyncUrlboxResponse response = await urlbox.Render(options);\n```\n\n## Using a Proxy\n\nProxies can really help get past issues like rendering social media sites, or sites that track your origin. We have a great piece in our [docs](https://urlbox.com/docs/guides/proxies) to get you started.\n\nSimply pass in the proxy providers' details once you're set up, and we will make the request through that proxy. Here's an example:\n\n```CS\nUrlbox urlbox = Urlbox.FromCredentials(\"YOUR_KEY\", \"YOUR_SECRET\", \"YOUR_WEBHOOK_SECRET\");\n\nUrlboxOptions options = Urlbox.Options(url: \"https://google.com\")\n    .Proxy(\"http://brd-customer-hl_1a2b3c4d-zone-social_networks:ttpg162fe6e2@brd.superproxy.io:22225\")\n    .Build();\n\nSyncUrlboxResponse response = await urlbox.Render(options);\n```\n\n## Using Webhooks\n\nWebhooks are awesome. They save you time, money and headaches, and can quite equally cause just as many setting them up. Setting up a webhook with Urlbox has some optional steps, but we recommend you take them all for the most security.\n\nPlease look at our example directory in the repo.\n\n### 1. Visit your Urlbox dashboard, and get your Webhook Secret.\n\nGo to your [projects](https://urlbox.com/dashboard/projects) page, select a project (you may only have one if you're just starting out with Urlbox), and copy the webhook secret key.\n\n### 2. Create your Urlbox instance in your C# project:\n\n```CS\nUrlbox urlbox = Urlbox.FromCredentials(\"YOUR_KEY\", \"YOUR_SECRET\", \"YOUR_WEBHOOK_SECRET\");\n```\n\n### 3. Make a request through any of our rendering methods. \n\nThe most common use case for a webhook is when you need to use the `/async` endpoint to handle a larger render.\n\nIf you're developing locally, we would recommend using a service like [ngrok](https://ngrok.com/), and setting your webhook URL in the options to that ngrok endpoint. \n\nAfter you've added the endpoint, for example at the endpoint `/webhooks/urlbox`, make a request to that endpoint like this:\n\n```CS\nstatic async Task Main()\n{\n    Urlbox urlbox = Urlbox.FromCredentials(\"YOUR_KEY\", \"YOUR_SECRET\", \"YOUR_WEBHOOK_SECRET\");\n    \n    UrlboxOptions options = Urlbox.Options(url: \"https://google.com\")\n      .WebhookUrl(\"https://myapp.com/webhooks/urlbox\")\n      .Build();\n\n    SyncUrlboxResponse response = await urlbox.Render(options);\n}\n```\n\n### 4. Verify that the webhook comes from Urlbox\n\nOnce you have made your request, you should see it come in as a POST request to the endpoint you've made in your app for the webhook. The body should look like this:\n\n```JSON\n{\n  \"event\": \"render.succeeded\",\n  \"renderId\": \"19a59ab6-a5aa-4cde-86cb-d2b23302fd84\",\n  \"result\": {\n    \"renderUrl\": \"https://renders.urlbox.com/urlbox1/renders/6215a3df94d7588f7d910513/2024/1/11/19a59ab6-a5aa-4cde-86cb-d2b23302fd84.png\",\n    \"size\": 34097\n  },\n  \"meta\": {\n    \"startTime\": \"2024-01-11T17:49:18.593Z\",\n    \"endTime\": \"2024-01-11T17:49:21.103Z\"\n  }\n}\n```\n\nThere will also be our header `X-Urlbox-Signature` that should have a value like this: `t={timestamp},sha256={token}`.\n\nExtract both the header and the content, and pass it into `Urlbox.VerifyWebhookSignature(header, content)`, which, if successful, will return you a [WebhookUrlboxResponse](#webhookurlboxresponse).\n\nPlease see the `Example` project in this repo which should help you get started.\n\n---\n\n# API Reference\n\nBelow is a brief description of every publicly available method our SDK provides:\n\n## Urlbox API Reference\n\n### Constructor\n- **`Urlbox(string key, string secret, string webhookSecret = null)`**  \n  Initializes a new instance of the Urlbox class with the provided API credentials and optional webhook secret.\n\n---\n\n### Static Methods\n- **`static Urlbox FromCredentials(string apiKey, string apiSecret, string webhookSecret)`**  \n  Creates a new instance of the Urlbox class using the specified API key, secret, and optional webhook secret.\n  \n- **`static UrlboxOptionsBuilder Options(string? url = null, string? html = null)`**  \n  Creates a new instance of the Urlbox options builder. Requires a URL or HTML in the constructor to get started.\n\n---\n\n### Screenshot and File Generation Methods\n\n- **`Task\u003cAsyncUrlboxResponse\u003e TakeScreenshot(UrlboxOptions options);`**\n- **`Task\u003cAsyncUrlboxResponse\u003e TakeScreenshot(UrlboxOptions options, int timeout);`**  \n  Takes a screenshot asynchronously with a polling mechanism. Optional timeout to dictate when to stop polling.\n\n- **`Task\u003cAsyncUrlboxResponse\u003e TakePdf(UrlboxOptions options);`**  \n  Asynchronously generates a PDF based on the specified options.\n\n- **`Task\u003cAsyncUrlboxResponse\u003e TakeMp4(UrlboxOptions options);`**  \n  Generates an MP4 video asynchronously using the specified options.\n\n- **`Task\u003cAsyncUrlboxResponse\u003e TakeFullPageScreenshot(UrlboxOptions options);`**  \n  Captures a full-page screenshot asynchronously with the given options.\n\n- **`Task\u003cAsyncUrlboxResponse\u003e TakeMobileScreenshot(UrlboxOptions options);`**  \n  Takes a mobile-optimized screenshot asynchronously based on the specified options.\n\n- **`Task\u003cAsyncUrlboxResponse\u003e TakeScreenshotWithMetadata(UrlboxOptions options);`**  \n  Asynchronously takes a screenshot and includes metadata in the response.\n\n- **`Task\u003cSyncUrlboxResponse\u003e Render(UrlboxOptions options);`**  \n- **`Task\u003cSyncUrlboxResponse\u003e Render(IDictionary\u003cstring, object\u003e options);`**\n  Sends a synchronous request to generate a render with the provided options, returning a direct response.\n\n- **`Task\u003cAsyncUrlboxResponse\u003e RenderAsync(UrlboxOptions options);`**  \n- **`Task\u003cAsyncUrlboxResponse\u003e RenderAsync(IDictionary\u003cstring, object\u003e options);`**  \n  Sends an asynchronous render request, providing a status URL for polling until completion.\n\n---\n\n### Download and File Handling Methods\n\n- **`Task\u003cstring\u003e DownloadAsBase64(UrlboxOptions options, string format = \"png\", bool sign = true);`**  \n  Downloads a screenshot as a Base64-encoded string in the specified format. Optional format and whether to sign the render link.\n\n- **`Task\u003cstring\u003e DownloadAsBase64(string urlboxUrl);`**  \n  Downloads the screenshot from the provided URL as a Base64-encoded string.\n\n- **`Task\u003cstring\u003e DownloadToFile(string urlboxUrl, string filename);`**  \n  Downloads a screenshot from the URL and saves it to the specified file path.\n\n- **`Task\u003cstring\u003e DownloadToFile(UrlboxOptions options, string filename, string format = \"png\", bool sign = true);`**  \n  Generates a screenshot based on options, then downloads and saves it as a file. Optional format and whether to sign the render link\n\n---\n\n### URL Generation Methods\n\n- **`string GeneratePNGUrl(UrlboxOptions options, bool sign = true);`**  \n  Generates a PNG URL based on the specified screenshot options.\n\n- **`string GenerateJPEGUrl(UrlboxOptions options, bool sign = true);`**  \n  Creates a JPEG URL using the provided rendering options.\n\n- **`string GeneratePDFUrl(UrlboxOptions options, bool sign = true);`**  \n  Generates a PDF URL for the specified screenshot options.\n\n- **`string GenerateRenderLink(UrlboxOptions options, string format = \"png\", bool sign = true);`**  \n  Constructs an Urlbox URL for the specified format and options.\n \n- **`string GenerateSignedRenderLink(UrlboxOptions options, string format = \"png\");`**  \n  Constructs an Urlbox URL for the specified format and options signed with the consumer's secret token.\n\n---\n\n### Status and Validation Methods\n\n- **`Task\u003cAsyncUrlboxResponse\u003e GetStatus(string renderId);`**  \n  Retrieves the current status of an asynchronous render request.\n\n- **`bool VerifyWebhookSignature(string header, string content);`**  \n  Verifies that a webhook signature originates from Urlbox using the configured webhook secret.\n\n\n### Response Classes\n\nWhen using the SDK, our deserializers will take the JSON response from any POST to the API and turn them into one of the following:\n\n#### `SyncUrlboxResponse`\n\nProperties:\n\n- **`RenderUrl`** - The URL to run a GET request to in order to access your final render.\n- **`Size`** - The size of the render in bytes.\n- **`HtmlUrl`** - The URL to run a GET request to in order to access your final render as HTML.\n- **`MhtmlUrl`** - The URL to run a GET request to in order to access your final render as MHTML.\n- **`MetadataUrl`** - The URL to run a GET request to in order to access your final render as Metadata (JSON).\n- **`MarkdownUrl`** - The URL to run a GET request to in order to access your final render as Markdown.\n- **`Metadata`** - The Metadata object describing the rendered website.\n\n#### `AsyncUrlboxResponse`\n\nProperties:\n\n- **`Status`** - One of `waiting`, `active`,  `failed`,  `delayed`,  `succeeded`.\n- **`RenderId`** - The unique ID of the render request.\n- **`StatusUrl`** - The URL to run a GET request to in order to find out if the render completed.\n- **`Size`** - The size of the render in bytes.\n- **`RenderUrl`** - The URL to run a GET request to in order to access your final render.\n- **`HtmlUrl`** - The URL to run a GET request to in order to access your final render as HTML.\n- **`MhtmlUrl`** - The URL to run a GET request to in order to access your final render as MHTML.\n- **`MetadataUrl`** - The URL to run a GET request to in order to access your final render as Metadata (JSON).\n- **`MarkdownUrl`** - The URL to run a GET request to in order to access your final render as Markdown.\n- **`Metadata`** - The Metadata object describing the rendered website.\n\n#### `WebhookUrlboxResponse`\n\nProperties:\n\n- **`Event`** - The event that happened to the render EG \"render.succeeded\"\n- **`RenderId`** - The unique ID of the render request.\n- **`Error`** - The error from Urlbox, showing the code, message and any errors\n- **`Result`** - An instance of the SyncUrlboxResponse\n- **`Meta`** - Includes the start and end times for the render\n\n#### `UrlboxException`\n\nProperties:\n\n- **`RequestId`** - The unique ID of the render request.\n- **`Code`** - The error code for the request. See a list [here](https://urlbox.com/docs/api#error-codes).\n- **`Errors`** - A more detailed list of errors that occurred in the request.\n\n#### `UrlboxMetadata`\n\nProperties:\n\n- **`UrlRequested`** - The original URL requested for rendering.\n- **`UrlResolved`** - The final resolved URL after any redirects.\n- **`Url`** - The canonical URL of the rendered page.\n- **`Author`** - The author of the content, if available.\n- **`Date`** - The publication date of the content, if available.\n- **`Description`** - The meta description of the page.\n- **`Image`** - The primary image of the page, if available.\n- **`Logo`** - The logo associated with the page or publisher.\n- **`Publisher`** - The name of the publisher of the content.\n- **`Title`** - The title of the page.\n- **`OgTitle`** - The Open Graph title of the page.\n- **`OgImages`** - A list of Open Graph images found on the page.\n- **`OgDescription`** - The Open Graph description of the page.\n- **`OgUrl`** - The Open Graph URL of the page.\n- **`OgType`** - The Open Graph type of the page (e.g., article, website).\n- **`OgSiteName`** - The Open Graph site name of the page.\n- **`OgLocale`** - The locale specified by Open Graph metadata.\n- **`Charset`** - The character encoding used by the page.\n- **`TwitterCard`** - The Twitter card type for the page.\n- **`TwitterSite`** - The Twitter site associated with the page.\n- **`TwitterCreator`** - The Twitter creator associated with the page.\n\n### Available Enums\n\nThere are a number of options which are one of a select few. We have made enums for these, which can be accessed directly from the UrlboxOptions namespace:\n\nColorProfile - one of `Colorspingamma24`, `Default`, `Dp3`, `Hdr10`, `Rec2020`, `Scrgblinear`, `Srgb`\n\nEngineVersion - one of `Latest`, `Lts`, `Stable`\n\nFormat - one of `Avif`, `Html`, `Jpeg`, `Jpg`, `Md`, `Mhtml`, `Mp4`, `Pdf`, `Png`, `Svg`, `Webm`, `Webp`\n\nFullPageMode - one of `Native`, `Stitch`\n\nImgFit - one of `Contain`, `Cover`, `Fill`, `Inside`, `Outside`\n\nImgPosition - one of `Attention`, `Bottom`, `Center`, `Centre`, `East`, `Entropy`, `Left`, `LeftBottom`, `LeftTop`, `North`, `Northeast`, `Northwest`, `Right`, `RightBottom`, `RightTop`, `South`, `Southeast`, `Southwest`, `Top`, `West`\n\nMedia - one of `Print`, `Screen`\n\nPdfMargin - one of `Default`, `Minimum`, `None`\n\nPdfOrientation - one of `Landscape`, `Portait`\n\nPdfPageSize - one of  `A0`, `A1`, `A2`, `A3`, `A4`, `A5`, `A6`, `Ledger`, `Legal`, `Letter`, `PdfPageSizeA0`, `PdfPageSizeA1`, `PdfPageSizeA2`, `PdfPageSizeA3`, `PdfPageSizeA4`, `PdfPageSizeA5`, `PdfPageSizeA6`, `PdfPageSizeLedger`, `PdfPageSizeLegal`, `PdfPageSizeLetter`, `PdfPageSizeTabloid`, `Tabloid`\n\nResponseType - one of `Base64`, `Binary`, `Json`, `Jsondebug`, `None`\n\nS3Storageclass - one of `DeepArchive`, `Glacier`, `IntelligentTiering`, `OnezoneIa`, `Outposts`, `ReducedRedundancy`, `S3StorageclassDeepArchive`, `S3StorageclassGlacier`, `S3StorageclassIntelligentTiering`, `S3StorageclassOnezoneIa`, `S3StorageclassOutposts`, `S3StorageclassReducedRedundancy`, `S3StorageclassStandard`, `S3StorageclassStandardIa`, `Standard`, `StandardIa`\n\nVideoCodec - one of `H264`, `Vp8`, `Vp9`\n\nVideoEase - one of `BackIn`, `BackInout`, `BackOut`, `BounceIn`, `BounceInout`, `BounceOut`, `CircularIn`, `CircularInout`, `CircularOut`, `CubicIn`, `CubicInout`, `CubicOut`, `ElasticIn`, `ElasticInout`, `ElasticOut`, `ExponentialIn`, `ExponentialInout`, `ExponentialOut`, `LinearNone`, `QuadraticIn`, `QuadraticInout`, `QuadraticOut`, `QuarticIn`, `QuarticInout`, `QuarticOut`, `QuinticIn`, `QuinticInout`, `QuinticOut`, `SinusoidalIn`, `SinusoidalInout`, `SinusoidalOut`\n\nVideoMethod - one of `Extension`, `Psr`, `Screencast`\n\nVideoPreset - one of `Fast`, `Faster`, `Medium`, `Slow`, `Slower`, `Superfast`, `Ultrafast`, `Veryfast`, `Veryslow`\n\nWaitUntil - one of `Domloaded`, `Loaded`, `Mostrequestsfinished`, `Requestsfinished`\n\n## Examples\n\n### [Example HTML](../Examples/html.html)\n### [Example PDF](../Examples/pdf.pdf)\n### [Example PDF Highlighting](../Examples/highlight.pdf)\n### [Example PNG injecting Javascript](../Examples/javascript.png)\n\n## Feedback\n\nWe hope that the above has given you enough of an understanding to suit your use case.\n\nIf you are still struggling, spot a bug, or have any suggestions, feel free to contact us at: `support@urlbox.com` or use our chat function on [our website](https://urlbox.com/).\n\nGet rendering!\n\n## Changelog\n\n- 2.0.0 - Major overhaul - **Non-backward compatible changes included.**\n  - Introduced fluent options builder with input validation.\n  - Introduced options as a typed class.\n  - Introduced webhook validation logic.\n  - Upgraded test suite.\n  - Created interfaces for DI.\n  - Introduced post sync and async methods.\n  - Introduced helper methods for common use cases.\n  - Overhauled readme including an API reference.\n  - Introduced logic and classes for side renders (save_html etc).\n  - Introduced classes for different response types from urlbox api.\n  - Added overhauls for render/renderAsync which take IDictionary for future proofing.\n  - Overhauls readme.\n\nMethods in previous versions of this SDK that would accept a Dictionary now take a standardised `UrlboxOptions` type.\n\n- 1.0.2 - Further Updates to readme.\n \n- 1.0.1 - Update Readme to replace instances of .io with .com.\n\n- 1.0.0 - First release!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furlbox%2Furlbox-dotnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Furlbox%2Furlbox-dotnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furlbox%2Furlbox-dotnet/lists"}