|
| 1 | +## 1. Create a Worker project |
| 2 | + |
| 3 | +[Cloudflare Workers](/workers/) provides a serverless execution environment that allows you to create new applications or augment existing ones without configuring or maintaining infrastructure. Your Worker application is a container to interact with a headless browser to do actions, such as taking screenshots. |
| 4 | + |
| 5 | +Create a new Worker project named `browser-worker` by running: |
| 6 | + |
| 7 | +<PackageManagers |
| 8 | + type="create" |
| 9 | + pkg="cloudflare@latest" |
| 10 | + args={"browser-worker"} |
| 11 | +/> |
| 12 | + |
| 13 | +<Render |
| 14 | + file="c3-post-run-steps" |
| 15 | + product="workers" |
| 16 | + params={{ |
| 17 | + category: "hello-world", |
| 18 | + type: "Worker only", |
| 19 | + lang: "JavaScript / TypeScript", |
| 20 | + }} |
| 21 | +/> |
| 22 | + |
| 23 | +## 2. Install Puppeteer |
| 24 | + |
| 25 | +In your `browser-worker` directory, install Cloudflare’s [fork of Puppeteer](/browser-rendering/platform/puppeteer/): |
| 26 | + |
| 27 | +<PackageManagers pkg="@cloudflare/puppeteer" dev /> |
| 28 | + |
| 29 | +## 3. Create a KV namespace |
| 30 | + |
| 31 | +Browser Rendering can be used with other developer products. You might need a [relational database](/d1/), an [R2 bucket](/r2/) to archive your crawled pages and assets, a [Durable Object](/durable-objects/) to keep your browser instance alive and share it with multiple requests, or [Queues](/queues/) to handle your jobs asynchronous. |
| 32 | + |
| 33 | +For the purpose of this guide, you are going to use a [KV store](/kv/concepts/kv-namespaces/) to cache your screenshots. |
| 34 | + |
| 35 | +Create two namespaces, one for production, and one for development. |
| 36 | + |
| 37 | +```sh |
| 38 | +npx wrangler kv namespace create BROWSER_KV_DEMO |
| 39 | +npx wrangler kv namespace create BROWSER_KV_DEMO --preview |
| 40 | +``` |
| 41 | + |
| 42 | +Take note of the IDs for the next step. |
| 43 | + |
| 44 | +## 4. Configure the Wrangler configuration file |
| 45 | + |
| 46 | +Configure your `browser-worker` project's [Wrangler configuration file](/workers/wrangler/configuration/) by adding a browser [binding](/workers/runtime-apis/bindings/) and a [Node.js compatibility flag](/workers/configuration/compatibility-flags/#nodejs-compatibility-flag). Bindings allow your Workers to interact with resources on the Cloudflare developer platform. Your browser `binding` name is set by you, this guide uses the name `MYBROWSER`. Browser bindings allow for communication between a Worker and a headless browser which allows you to do actions such as taking a screenshot, generating a PDF and more. |
| 47 | + |
| 48 | +Update your [Wrangler configuration file](/workers/wrangler/configuration/) with the Browser Rendering API binding and the KV namespaces you created: |
| 49 | + |
| 50 | +<WranglerConfig> |
| 51 | + |
| 52 | +```toml title="wrangler.toml" |
| 53 | +name = "browser-worker" |
| 54 | +main = "src/index.js" |
| 55 | +compatibility_date = "2023-03-14" |
| 56 | +compatibility_flags = [ "nodejs_compat" ] |
| 57 | + |
| 58 | +browser = { binding = "MYBROWSER" } |
| 59 | +kv_namespaces = [ |
| 60 | + { binding = "BROWSER_KV_DEMO", id = "22cf855786094a88a6906f8edac425cd", preview_id = "e1f8b68b68d24381b57071445f96e623" } |
| 61 | +] |
| 62 | +``` |
| 63 | + |
| 64 | +</WranglerConfig> |
| 65 | + |
| 66 | +## 5. Code |
| 67 | + |
| 68 | +<Tabs> <TabItem label="JavaScript" icon="seti:javascript"> |
| 69 | +Update `src/index.js` with your Worker code: |
| 70 | + |
| 71 | +```js |
| 72 | +import puppeteer from "@cloudflare/puppeteer"; |
| 73 | + |
| 74 | +export default { |
| 75 | + async fetch(request, env) { |
| 76 | + const { searchParams } = new URL(request.url); |
| 77 | + let url = searchParams.get("url"); |
| 78 | + let img; |
| 79 | + if (url) { |
| 80 | + url = new URL(url).toString(); // normalize |
| 81 | + img = await env.BROWSER_KV_DEMO.get(url, { type: "arrayBuffer" }); |
| 82 | + if (img === null) { |
| 83 | + const browser = await puppeteer.launch(env.MYBROWSER); |
| 84 | + const page = await browser.newPage(); |
| 85 | + await page.goto(url); |
| 86 | + img = await page.screenshot(); |
| 87 | + await env.BROWSER_KV_DEMO.put(url, img, { |
| 88 | + expirationTtl: 60 * 60 * 24, |
| 89 | + }); |
| 90 | + await browser.close(); |
| 91 | + } |
| 92 | + return new Response(img, { |
| 93 | + headers: { |
| 94 | + "content-type": "image/jpeg", |
| 95 | + }, |
| 96 | + }); |
| 97 | + } else { |
| 98 | + return new Response("Please add an ?url=https://example.com/ parameter"); |
| 99 | + } |
| 100 | + }, |
| 101 | +}; |
| 102 | +``` |
| 103 | + |
| 104 | +</TabItem> <TabItem label="TypeScript" icon="seti:typescript"> |
| 105 | +Update `src/index.ts` with your Worker code: |
| 106 | + |
| 107 | +```ts |
| 108 | +import puppeteer from "@cloudflare/puppeteer"; |
| 109 | + |
| 110 | +interface Env { |
| 111 | + MYBROWSER: Fetcher; |
| 112 | + BROWSER_KV_DEMO: KVNamespace; |
| 113 | +} |
| 114 | + |
| 115 | +export default { |
| 116 | + async fetch(request, env): Promise<Response> { |
| 117 | + const { searchParams } = new URL(request.url); |
| 118 | + let url = searchParams.get("url"); |
| 119 | + let img: Buffer; |
| 120 | + if (url) { |
| 121 | + url = new URL(url).toString(); // normalize |
| 122 | + img = await env.BROWSER_KV_DEMO.get(url, { type: "arrayBuffer" }); |
| 123 | + if (img === null) { |
| 124 | + const browser = await puppeteer.launch(env.MYBROWSER); |
| 125 | + const page = await browser.newPage(); |
| 126 | + await page.goto(url); |
| 127 | + img = (await page.screenshot()) as Buffer; |
| 128 | + await env.BROWSER_KV_DEMO.put(url, img, { |
| 129 | + expirationTtl: 60 * 60 * 24, |
| 130 | + }); |
| 131 | + await browser.close(); |
| 132 | + } |
| 133 | + return new Response(img, { |
| 134 | + headers: { |
| 135 | + "content-type": "image/jpeg", |
| 136 | + }, |
| 137 | + }); |
| 138 | + } else { |
| 139 | + return new Response("Please add an ?url=https://example.com/ parameter"); |
| 140 | + } |
| 141 | + }, |
| 142 | +} satisfies ExportedHandler<Env>; |
| 143 | +``` |
| 144 | + |
| 145 | +</TabItem> </Tabs> |
| 146 | + |
| 147 | +This Worker instantiates a browser using Puppeteer, opens a new page, navigates to what you put in the `"url"` parameter, takes a screenshot of the page, stores the screenshot in KV, closes the browser, and responds with the JPEG image of the screenshot. |
| 148 | + |
| 149 | +If your Worker is running in production, it will store the screenshot to the production KV namespace. If you are running `wrangler dev`, it will store the screenshot to the dev KV namespace. |
| 150 | + |
| 151 | +If the same `"url"` is requested again, it will use the cached version in KV instead, unless it expired. |
| 152 | + |
| 153 | +## 6. Test |
| 154 | + |
| 155 | +Run `npx wrangler dev` to test your Worker locally or run [`npx wrangler dev --remote`](/workers/wrangler/commands/#dev) to test your Worker remotely before deploying to Cloudflare's global network. |
| 156 | + |
| 157 | +To test taking your first screenshot, go to the following URL: |
| 158 | + |
| 159 | +`<LOCAL_HOST_URL>/?url=https://example.com` |
| 160 | + |
| 161 | +## 7. Deploy |
| 162 | + |
| 163 | +Run `npx wrangler deploy` to deploy your Worker to the Cloudflare global network. |
| 164 | + |
| 165 | +To take your first screenshot, go to the following URL: |
| 166 | + |
| 167 | +`<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/?url=https://example.com` |
0 commit comments