diff --git a/README.md b/README.md
index f446fc2..1a20aa7 100644
--- a/README.md
+++ b/README.md
@@ -1,59 +1,14 @@
-![Netlify examples](https://user-images.githubusercontent.com/5865/159468750-df1c2783-39b2-40da-9c0f-971f72a7ea3f.png)
+![Netlify examples](https://github.com/netlify/edge-functions-examples/assets/7912948/d34a626d-1c65-492d-bb14-85f50d9b72cb)
 
-# [Netlify Edge Functions](https://www.netlify.com/products/?utm_campaign=devex&utm_source=edge-functions-examples&utm_medium=github&utm_content=Edge%20Functions%20Product%20Page#netlify-edge-functions) Examples
-
-Explore these examples here: https://edge-functions-examples.netlify.app/
-
-## Responses
-
-- [Hello, world](/pages/hello)
-- [Return JSON](/pages/json)
-- [Return an image](/pages/image)
-
-## Rewrites and proxies
-
-- [Rewrite responses from another URL](/pages/rewrite)
-- [Proxy requests to another source](/pages/proxy-requests)
-
-## HTTP Headers
-
-- [Set custom HTTP request headers](/pages/set-request-header)
-- [Set custom HTTP response headers](/pages/set-response-header)
-
-## Transforming responses
 
-- [Text transformation](/pages/transform)
-- [Content includes](/pages/include)
-
-## Geolocation
-
-- [Determine a user's location](/pages/geolocation)
-- [Block content according to country](/pages/country-block)
-- [Serve localized content](/pages/localized-content)
-
-## Cookies
-
-- [Set cookies](/pages/cookies-set)
-- [Read cookies](/pages/cookies-read)
-- [Delete cookies](/pages/cookies-delete)
-- [Set up an A/B test using cookies](/pages/abtest)
-
-## Streams
-- [Long-running edge functions](/pages/long-running)
-- [Server-sent events](/pages/server-sent-events)
-
-## WebAssembly
-- [Edge WebAssembly](/pages/wasm)
-
-## Environment and debugging
+# [Netlify Edge Functions](https://www.netlify.com/products/?utm_campaign=devex&utm_source=edge-functions-examples&utm_medium=github&utm_content=Edge%20Functions%20Product%20Page#netlify-edge-functions) Examples
 
-- [Write to the logs](/pages/log)
-- [Use environment variables](/pages/environment)
+Try these examples here: https://edge-functions-examples.netlify.app/
 
 ---
 
-## Deploy this site to Netlify
+## This code has a new home
 
-Click this button to deploy this site automatically to your Netlify account.
+This repo has been migrated into the [Netlify Examples monorepo](https://github.com/netlify/examples/tree/main/examples/edge-functions ).
 
-[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/netlify/edge-functions-examples&utm_campaign=devex&utm_source=edge-functions-examples&utm_medium=web&utm_content=Deploy%20Edge%20Functions%20Examples%20to%20Netlify)
+Explore the code for these examples, along with many others here: https://github.com/netlify/examples/
diff --git a/components/layout.js b/components/layout.js
index 6ba5d3a..152d7b1 100644
--- a/components/layout.js
+++ b/components/layout.js
@@ -7,7 +7,7 @@ const explainer = `
 <section>
   <h2>What are Edge Functions?</h2>
   <p>Using JavaScript and TypeScript, <a href="https://www.netlify.com/products/?utm_campaign=devex&utm_source=edge-functions-examples&utm_medium=web&utm_content=Edge%20Functions%20Product%20Page#netlify-edge-functions" target="_blank" rel="noopener">Netlify Edge Functions</a> give you the power to modify network requests to localize content, serve relevant ads, authenticate visitors, A/B test content, and much more! And this all happens at the <strong>Edge</strong> — directly from the worldwide location closest to each user.</p>
-  <p>To use Edge Functions on Netlify, add JavaScript or TypeScript files to an edge-functions directory in your project, and add <code>[[edge_functions]]</code> entries to your netlify.toml file.</p>
+  <p>To use Edge Functions on Netlify, add JavaScript or TypeScript files to an edge-functions directory in your project.</p>
   <p><a href="https://docs.netlify.com/edge-functions/overview/?utm_campaign=devex&utm_source=edge-functions-examples&utm_medium=web&utm_content=Edge%20Functions%20Docs" target="_blank" rel="noopener">Learn more in the docs</a>.</p>
 </section>
 `;
@@ -39,7 +39,9 @@ export default function layout(data) {
     ${data.content}
     </section>
     <p>
-      ${data.url.pathname !== "/" ? `<a href="/">Explore more examples</a>` : ""}
+      ${
+        data.url.pathname !== "/" ? `<a href="/">Explore more examples</a>` : ""
+      }
     </p>
 
     ${data.url.pathname !== "/" ? explainer : ""}
diff --git a/netlify.toml b/netlify.toml
index 434ffac..ae0c4a5 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -1,123 +1,19 @@
 [dev]
-  framework = "#static"
+framework = "#static"
 
 [build]
-  command = "echo No build for this site, we are living on the edge"
-  publish = "public"
+command = "echo No build for this site, we are living on the edge"
+publish = "public"
 
 [context.production]
-  environment = { MY_IMPORTANT_VARIABLE = "this is a very important secret" }
+environment = { MY_IMPORTANT_VARIABLE = "this is a very important secret" }
 
-# The URL for each edge function
-[[edge_functions]]
-  function = "transform"
-  path = "/*"
-  
-[[edge_functions]]
-  function = "set-response-header"
-  path = "/*"
-
-[[edge_functions]]
-  function = "set-request-header"
-  path = "/*"
 
-[[edge_functions]]
-  function = "method"
-  path = "/method"
+[[redirects]]
+from = "/img/og/:text"
+to = "https://res.cloudinary.com/netlify/image/upload/c_fit,g_west,h_400,co_rgb:FFFFFFFF,l_text:netlify.com:Pacaembu-Bold.ttf_57::text,w_1053,x_46/v1619123320/netlify.com/default-og-background-learn-more.png"
+status = 200
 
 [[edge_functions]]
-  function = "include"
+  function = "transform"
   path = "/*"
-
-[[edge_functions]]
-  path = "/hello"
-  function = "hello"
-
-[[edge_functions]]
-  path = "/geolocation"
-  function = "geolocation"
-
-[[edge_functions]]
-  path = "/json"
-  function = "json"
-
-[[edge_functions]]
-  path = "/cookies"
-  function = "cookies"
-
-[[edge_functions]]
-  path = "/rewrite"
-  function = "rewrite"
-
-[[edge_functions]]
-  path = "/abtest"
-  function = "abtest"
-
-[[edge_functions]]
-  path = "/image-internal"
-  function = "image-internal"
-
-[[edge_functions]]
-  path = "/image-external"
-  function = "image-external"
-  
-[[edge_functions]]
-  path = "/log"
-  function = "log"
-
-[[edge_functions]]
-  path = "/country-block"
-  function = "country-block"
-
-[[edge_functions]]
-  path = "/localized-content"
-  function = "localized-content"
-
-[[edge_functions]]
-  path = "/fetch-joke"
-  function = "proxy-requests"
-
-[[edge_functions]]
-  path = "/environment"
-  function = "environment"
-
-[[edge_functions]]
-  path = "/error"
-  function = "error"
-
-[[edge_functions]]
-  path = "/long-running"
-  function = "long-running"
-
-[[edge_functions]]
-  path = "/sse"
-  function = "sse"
-
-[[edge_functions]]
-  path = "/context-site"
-  function = "context-site"
-
-[[edge_functions]]
-  path = "/wasm"
-  function = "wasm"
-
-# Serve pages explaining each example 
-[[edge_functions]]
-  path = "/example/*"
-  function = "[page]"
-
-# Serve our index page
-[[edge_functions]]
-  path = "/"
-  function = "[page]"
-
-[[redirects]]
-  from = "/img/og/:text"
-  to = "https://res.cloudinary.com/netlify/image/upload/c_fit,g_west,h_400,co_rgb:FFFFFFFF,l_text:netlify.com:Pacaembu-Bold.ttf_57::text,w_1053,x_46/v1619123320/netlify.com/default-og-background-learn-more.png"
-  status = 200
-
-
-
-
-
-
diff --git a/netlify/edge-functions/[page].js b/netlify/edge-functions/[page].js
index 925564f..7327927 100644
--- a/netlify/edge-functions/[page].js
+++ b/netlify/edge-functions/[page].js
@@ -8,6 +8,7 @@ import layout from "../../components/layout.js";
 import pageHome from "../../pages/home/index.js";
 import pageHello from "../../pages/hello/index.js";
 import pageTransform from "../../pages/transform/index.js";
+import pageHtmlrewriter from "../../pages/htmlrewriter/index.js";
 import pageInclude from "../../pages/include/index.js";
 import pageRewrite from "../../pages/rewrite/index.js";
 import pageGeolocation from "../../pages/geolocation/index.js";
@@ -40,7 +41,7 @@ const pages = {
   json: pageJson,
   "set-response-header": pageSetResponseHeader,
   "set-request-header": pageSetRequestHeader,
-  "method": pageMethod,
+  method: pageMethod,
   "cookies-set": pageCookiesSet,
   "cookies-read": pageCookiesRead,
   "cookies-delete": pageCookiesDelete,
@@ -55,14 +56,15 @@ const pages = {
   environment: pageEnvironment,
   "uncaught-exceptions": pageUncaughtExceptions,
   "context-site": pageContextSite,
-  "wasm": pageWasm,
+  wasm: pageWasm,
   "server-sent-events": pageSse,
   "long-running": pageLongRunning,
+  htmlrewriter: pageHtmlrewriter,
 };
 
 export default (request, context) => {
   const url = new URL(request.url);
-  const path = url.pathname.split("/example/")[1] || "home";
+  const path = context.params?.page || "home";
 
   console.log(`serve page for ${url} `);
 
@@ -79,3 +81,7 @@ export default (request, context) => {
     headers: { "content-type": "text/html" },
   });
 };
+
+export const config = {
+  path: ["/", "/example/:page"],
+};
diff --git a/netlify/edge-functions/abtest.ts b/netlify/edge-functions/abtest.ts
index 6b4ec59..bbcfa4d 100644
--- a/netlify/edge-functions/abtest.ts
+++ b/netlify/edge-functions/abtest.ts
@@ -1,4 +1,4 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   // look for existing "test_bucket" cookie
@@ -29,3 +29,7 @@ export default async (request: Request, context: Context) => {
     `Congratulations! You have been assigned ${bucketName} **${newBucketValue}**. View your browser cookies to check it out!`,
   );
 };
+
+export const config: Config = {
+  path: "/abtest",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/context-site.ts b/netlify/edge-functions/context-site.ts
index 08b4be1..163d0ee 100644
--- a/netlify/edge-functions/context-site.ts
+++ b/netlify/edge-functions/context-site.ts
@@ -1,5 +1,9 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   return new Response(`Hello from ${context.site.name}!`);
 };
+
+export const config: Config = {
+  path: "/context-site",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/cookies.ts b/netlify/edge-functions/cookies.ts
index 211e697..92bc8fb 100644
--- a/netlify/edge-functions/cookies.ts
+++ b/netlify/edge-functions/cookies.ts
@@ -1,4 +1,4 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   const url = new URL(request.url);
@@ -27,3 +27,7 @@ export default async (request: Request, context: Context) => {
 
   return new Response(message);
 };
+
+export const config: Config = {
+  path: "/cookies",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/country-block.ts b/netlify/edge-functions/country-block.ts
index d247f4f..661d5ca 100644
--- a/netlify/edge-functions/country-block.ts
+++ b/netlify/edge-functions/country-block.ts
@@ -1,4 +1,4 @@
-import { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   // Here's what's available on context.geo
@@ -32,3 +32,7 @@ export default async (request: Request, context: Context) => {
     headers: { "content-type": "text/html" },
   });
 };
+
+export const config: Config = {
+  path: "/country-block",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/environment.ts b/netlify/edge-functions/environment.ts
index 7632571..9fb6d75 100644
--- a/netlify/edge-functions/environment.ts
+++ b/netlify/edge-functions/environment.ts
@@ -1,4 +1,4 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   const value = Netlify.env.get("MY_IMPORTANT_VARIABLE");
@@ -7,3 +7,7 @@ export default async (request: Request, context: Context) => {
     headers: { "content-type": "text/html" },
   });
 };
+
+export const config: Config = {
+  path: "/environment",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/error.ts b/netlify/edge-functions/error.ts
index 94c50aa..a60cd44 100644
--- a/netlify/edge-functions/error.ts
+++ b/netlify/edge-functions/error.ts
@@ -1,3 +1,7 @@
 export default async () => {
   throw new Error("💥");
 };
+
+export const config = {
+  path: "/error",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/geolocation.ts b/netlify/edge-functions/geolocation.ts
index f37a5d5..cc7f694 100644
--- a/netlify/edge-functions/geolocation.ts
+++ b/netlify/edge-functions/geolocation.ts
@@ -1,4 +1,5 @@
-import { Context } from "@netlify/edge-functions";
+import type { Config, Context } from "@netlify/edge-functions";
+
 
 export default async (request: Request, context: Context) => {
   // Here's what's available on context.geo
@@ -24,3 +25,7 @@ export default async (request: Request, context: Context) => {
     geo: context.geo,
   });
 };
+
+export const config: Config = {
+  path: "/geolocation",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/hello.js b/netlify/edge-functions/hello.js
index 4de5bcc..0d6ce29 100644
--- a/netlify/edge-functions/hello.js
+++ b/netlify/edge-functions/hello.js
@@ -3,3 +3,7 @@ export default async (request) => {
     headers: { "content-type": "text/html" },
   });
 };
+
+export const config = {
+  path: "/hello",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/htmlrewriter.ts b/netlify/edge-functions/htmlrewriter.ts
new file mode 100644
index 0000000..aa70a8a
--- /dev/null
+++ b/netlify/edge-functions/htmlrewriter.ts
@@ -0,0 +1,35 @@
+import { Config, Context } from "@netlify/edge-functions";
+import { HTMLRewriter } from "https://ghuc.cc/worker-tools/html-rewriter/index.ts";
+
+export default async function handler(request: Request, context: Context) {
+  const url = new URL(request.url);
+  if (!url.searchParams.has("catify")) {
+    return;
+  }
+
+  const location = context?.geo?.city;
+
+  const response = await context.next();
+  const rewriter = new HTMLRewriter()
+    .on("#location", {
+      element: (element) => {
+        element.setInnerContent(`Catified for a visitor in ${location}`);
+      },
+    })
+    .on("img[catify]", {
+      element: (element) => {
+        const width = element.getAttribute("width") ?? 800;
+        const height = element.getAttribute("height") ?? 600;
+        element.setAttribute(
+          "src",
+          `https://placekitten.com/${width}/${height}`
+        );
+        element.setAttribute("alt", "A random cat");
+      },
+    });
+  return rewriter.transform(response);
+}
+
+export const config: Config = {
+  path: "/a-static-page",
+};
diff --git a/netlify/edge-functions/image-external.ts b/netlify/edge-functions/image-external.ts
index 99773bb..627359e 100644
--- a/netlify/edge-functions/image-external.ts
+++ b/netlify/edge-functions/image-external.ts
@@ -1,4 +1,4 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 // Let's serve an image of a kitten from the internet
 
@@ -9,3 +9,7 @@ export default async (request: Request, context: Context) => {
   const kitten = await fetch("https://placekitten.com/g/300/300");
   return kitten;
 };
+
+export const config: Config = {
+  path: "/image-external",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/image-internal.ts b/netlify/edge-functions/image-internal.ts
index 72a68d2..25400c4 100644
--- a/netlify/edge-functions/image-internal.ts
+++ b/netlify/edge-functions/image-internal.ts
@@ -1,4 +1,4 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 // Let's serve an image that's stored in the repo
 // by rewriting the URL.
@@ -6,3 +6,7 @@ import type { Context } from "@netlify/edge-functions";
 export default async (request: Request, context: Context) => {
   return new URL("/apple-touch-icon.png", request.url);
 };
+
+export const config: Config = {
+  path: "/image-internal",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/include.ts b/netlify/edge-functions/include.ts
index 1bf804c..9e2440b 100644
--- a/netlify/edge-functions/include.ts
+++ b/netlify/edge-functions/include.ts
@@ -1,4 +1,4 @@
-import { Context } from "@netlify/edge-functions";
+import { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   
@@ -23,3 +23,7 @@ export default async (request: Request, context: Context) => {
   const updatedPage = page.replace(regex, pricingContent);
   return new Response(updatedPage, response);
 };
+
+export const config: Config = {
+  path: "/*",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/json.ts b/netlify/edge-functions/json.ts
index bd7952a..6a9a3ef 100644
--- a/netlify/edge-functions/json.ts
+++ b/netlify/edge-functions/json.ts
@@ -1,5 +1,9 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   return Response.json({ hello: "world" });
 };
+
+export const config: Config = {
+  path: "/json",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/localized-content.js b/netlify/edge-functions/localized-content.js
index 7a81319..575cefd 100644
--- a/netlify/edge-functions/localized-content.js
+++ b/netlify/edge-functions/localized-content.js
@@ -14,3 +14,7 @@ export default async (request, context) => {
     headers: { "content-type": "text/html" },
   });
 };
+
+export const config = {
+  path: "/localized-content",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/log.ts b/netlify/edge-functions/log.ts
index 23419e9..0fe4962 100644
--- a/netlify/edge-functions/log.ts
+++ b/netlify/edge-functions/log.ts
@@ -1,4 +1,4 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   console.log("Hello from the logging service");
@@ -7,3 +7,7 @@ export default async (request: Request, context: Context) => {
     headers: { "content-type": "text/html" },
   });
 };
+
+export const config: Config = {
+  path: "/log",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/long-running.ts b/netlify/edge-functions/long-running.ts
index f750045..06d5508 100644
--- a/netlify/edge-functions/long-running.ts
+++ b/netlify/edge-functions/long-running.ts
@@ -1,4 +1,4 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 function doSomethingSlow(): Promise<string> {
   return new Promise((resolve) => {
@@ -22,3 +22,7 @@ export default (request: Request, context: Context) => {
     },
   });
 };
+
+export const config: Config = {
+  path: "/long-running",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/method.ts b/netlify/edge-functions/method.ts
index 3c0951b..48238f9 100644
--- a/netlify/edge-functions/method.ts
+++ b/netlify/edge-functions/method.ts
@@ -6,5 +6,6 @@ export default async (request: Request, context: Context) => {
 };
 
 export const config: Config = {
+  path: "/method",
   method: ["POST", "PUT"]
 }
diff --git a/netlify/edge-functions/proxy-requests.ts b/netlify/edge-functions/proxy-requests.ts
index db9cf01..9d3f6eb 100644
--- a/netlify/edge-functions/proxy-requests.ts
+++ b/netlify/edge-functions/proxy-requests.ts
@@ -1,4 +1,4 @@
-import { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
 
@@ -10,3 +10,7 @@ export default async (request: Request, context: Context) => {
   const jsonData = await joke.json();
   return Response.json(jsonData);
 };
+
+export const config: Config = {
+  path: "/fetch-joke",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/rewrite.ts b/netlify/edge-functions/rewrite.ts
index f56e258..d4ec350 100644
--- a/netlify/edge-functions/rewrite.ts
+++ b/netlify/edge-functions/rewrite.ts
@@ -1,5 +1,8 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   return new URL("/something-to-serve-with-a-rewrite", request.url);
 };
+export const config: Config = {
+  path: "/rewrite",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/set-request-header.ts b/netlify/edge-functions/set-request-header.ts
index d6da6a9..9af3346 100644
--- a/netlify/edge-functions/set-request-header.ts
+++ b/netlify/edge-functions/set-request-header.ts
@@ -1,5 +1,9 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   request.headers.set("X-Your-Custom-Header", "Your custom header value");
 };
+
+export const config: Config = {
+  path: "/*",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/set-response-header.ts b/netlify/edge-functions/set-response-header.ts
index 74b4057..d2527e2 100644
--- a/netlify/edge-functions/set-response-header.ts
+++ b/netlify/edge-functions/set-response-header.ts
@@ -1,4 +1,4 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   const url = new URL(request.url);
@@ -13,3 +13,7 @@ export default async (request: Request, context: Context) => {
   response.headers.set("X-Your-Custom-Header", "Your custom header value");
   return response;
 };
+
+export const config: Config = {
+  path: "/*",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/sse.ts b/netlify/edge-functions/sse.ts
index b6b6ce2..c26f532 100644
--- a/netlify/edge-functions/sse.ts
+++ b/netlify/edge-functions/sse.ts
@@ -1,4 +1,4 @@
-import type { Context } from "@netlify/edge-functions";
+import type { Context, Config } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   let index = 0
@@ -16,3 +16,7 @@ export default async (request: Request, context: Context) => {
     },
   });
 };
+
+export const config: Config = {
+  path: "/sse",
+};
\ No newline at end of file
diff --git a/netlify/edge-functions/transform.ts b/netlify/edge-functions/transform.ts
index 784b271..41f92f1 100644
--- a/netlify/edge-functions/transform.ts
+++ b/netlify/edge-functions/transform.ts
@@ -1,4 +1,4 @@
-import { Context } from "@netlify/edge-functions";
+import type { Config, Context } from "@netlify/edge-functions";
 
 export default async (request: Request, context: Context) => {
   const url = new URL(request.url);
diff --git a/netlify/edge-functions/wasm.ts b/netlify/edge-functions/wasm.ts
index c346b68..8f2d2fd 100644
--- a/netlify/edge-functions/wasm.ts
+++ b/netlify/edge-functions/wasm.ts
@@ -14,4 +14,8 @@ const main = wasmInstance.exports.main as CallableFunction;
 
 export default async () => {
   return new Response(`The answer is ${main().toString()}`);
-}
\ No newline at end of file
+}
+
+export const config = {
+  path: "/wasm",
+};
\ No newline at end of file
diff --git a/pages/home/index.js b/pages/home/index.js
index 29f8b8a..0d4cd10 100644
--- a/pages/home/index.js
+++ b/pages/home/index.js
@@ -1,8 +1,9 @@
 export default {
   title: "Home",
-  metaDescription: "Explore our library of Edge Function examples and deploy your own to Netlify.",
+  metaDescription:
+    "Explore our library of Edge Function examples and deploy your own to Netlify.",
   page: function () {
-    return /* html */`
+    return /* html */ `
     <section class="home__section">
     <h2>Examples</h2>
     <p>
@@ -40,6 +41,7 @@ export default {
       <h3 class="home__sectionHeader">Transforming responses</h3>
       <ul class="home__sectionList">
         <li class="home__sectionListItem"><a class="home__sectionListItemLink" href="/example/transform">Text transformations</a></li>
+        <li class="home__sectionListItem"><a class="home__sectionListItemLink" href="/example/htmlrewriter">HTML transformations</a></li>
         <li class="home__sectionListItem"><a class="home__sectionListItemLink" href="/example/include">Content includes</a></li>
       </ul>
     </section>
diff --git a/pages/htmlrewriter/README.md b/pages/htmlrewriter/README.md
new file mode 100644
index 0000000..d5672e9
--- /dev/null
+++ b/pages/htmlrewriter/README.md
@@ -0,0 +1,66 @@
+![Netlify examples](https://user-images.githubusercontent.com/5865/159468750-df1c2783-39b2-40da-9c0f-971f72a7ea3f.png)
+
+# Transform HTML responses with Netlify Edge Functions and HTMLRewriter
+
+You can use Edge Functions with the HTMLRewriter library to transform HTML
+responses. HTMLRewriter uses WebAssembly to parse a response stream, so is very
+efficient. It can parse large HTML pages with minimal overhead, and is a better
+choice than using a string transform in most cases. It has an API that uses
+familiar CSS selectors to target elements, and can be used to add, remove, or
+modify elements.
+
+In this example, we transform an HTML page, replacing the `src` of `<img>` tags
+with a placeholder image. We also add content with the user's location. This
+shows how to do user personalization when the pages may be static.
+
+## Code example
+
+Edge Functions are files held in the `netlify/edge-functions` directory.
+
+```ts
+import { Config, Context } from "@netlify/edge-functions";
+import { HTMLRewriter } from "https://ghuc.cc/worker-tools/html-rewriter/index.ts";
+
+export default async function handler(request: Request, context: Context) {
+  const url = new URL(request.url);
+  // Only run if the `catify` query parameter is set
+  if (!url.searchParams.has("catify")) {
+    return;
+  }
+
+  const location = context?.geo?.city;
+
+  const response = await context.next();
+  const rewriter = new HTMLRewriter()
+    .on("#location", {
+      element: (element) => {
+        element.setInnerContent(`Catified for a visitor in ${location}`);
+      },
+    })
+    .on("img[catify]", {
+      element: (element) => {
+        const width = element.getAttribute("width") ?? 800;
+        const height = element.getAttribute("height") ?? 600;
+        element.setAttribute(
+          "src",
+          `https://placekitten.com/${width}/${height}`
+        );
+        element.setAttribute("alt", "A random cat");
+      },
+    });
+  return rewriter.transform(response);
+}
+```
+
+- [Explore the code for this Edge Function](../../netlify/edge-functions/htmlrewriter.ts)
+
+## View this example on the web
+
+- https://edge-functions-examples.netlify.app/example/htmlrewriter/
+
+## Deploy to Netlify
+
+You can deploy this and all the other examples in this repo as a site of your
+own to explore and experiment with, by clicking this button.
+
+[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/netlify/edge-functions-examples&utm_campaign=devex&utm_source=edge-functions-examples&utm_medium=web&utm_content=Deploy%20Edge%20Functions%20Examples%20to%20Netlify)
diff --git a/pages/htmlrewriter/index.js b/pages/htmlrewriter/index.js
new file mode 100644
index 0000000..5295fcf
--- /dev/null
+++ b/pages/htmlrewriter/index.js
@@ -0,0 +1,67 @@
+import repoLink from "../../components/repo-link.js";
+
+export default {
+  title: "Transform HTML Response stream",
+  metaDescription: "Dynamically transform any HTML response at the edge.",
+  page: function () {
+    return /* html */ `
+    <section>
+      <h1>Transform HTML responses with Netlify Edge Functions and HTMLRewriter</h1>
+      <p>
+      You can use Edge Functions with the HTMLRewriter library to transform HTML
+      responses. HTMLRewriter uses WebAssembly to parse a response stream, so is very
+      efficient. It can parse large HTML pages with minimal overhead, and is a better
+      choice than using a string transform in most cases. It has an API that uses
+      familiar CSS selectors to target elements, and can be used to add, remove, or
+      modify elements.
+    </p>
+      <p>
+      In this example, we transform an HTML page, replacing the <code>src</code> of <code><img></code> tags
+      with a placeholder image. We also add content with the user's location. This
+      shows how to do user personalization when the pages may be static.      
+    </p>
+
+      <pre><code>import { Config, Context } from "@netlify/edge-functions";
+import { HTMLRewriter } from "https://ghuc.cc/worker-tools/html-rewriter/index.ts";
+
+export default async function handler(request: Request, context: Context) {
+  const url = new URL(request.url);
+  // Only run if the catify query parameter is set
+  if (!url.searchParams.has("catify")) {
+    return;
+  }
+
+  const location = context?.geo?.city;
+
+  const response = await context.next();
+  const rewriter = new HTMLRewriter()
+    .on("#location", {
+      element: (element) => {
+        element.setInnerContent(\`Catified for a visitor in \${location}\`);
+      },
+    })
+    .on("img[catify]", {
+      element: (element) => {
+        const width = element.getAttribute("width") ?? 800;
+        const height = element.getAttribute("height") ?? 600;
+        element.setAttribute(
+          "src",
+          \`https://placekitten.com/\${width}/\${height}\`
+        );
+        element.setAttribute("alt", "A random cat");
+      },
+    });
+  return rewriter.transform(response);
+}
+</code></pre>
+
+      <h2>See this in action</h2>
+      <ul>
+        <li><a href="/a-static-page">View the original response from /a-static-page</a> without a transform</li>
+        <li>View the response from /a-static-page <a href="/a-static-page?catify">dynamically transformed with a HTMLRewriter</a></li>
+        <li>${repoLink("htmlrewriter.ts")}</li>
+      </ul>
+    </section>
+  `;
+  },
+};
diff --git a/pages/transform/index.js b/pages/transform/index.js
index 9b870e5..f1ff79f 100644
--- a/pages/transform/index.js
+++ b/pages/transform/index.js
@@ -10,6 +10,8 @@ export default {
       <p>
         You can use Edge Functions to transform the content of an HTTP response. In this example, we transform the response of a request to <a href="/hello">/hello</a> with a <code>toUpperCase()</code> function, using the query parameter <code>method=transform</code>.
       </p>
+      <p>This is a simple example, and for more complex transformations you may want to use <a href="/example/htmlrewriter">HTMLRewriter</a>.
+      </p>
 
       <pre><code>import { Context } from "@netlify/edge-functions";
 
@@ -27,11 +29,8 @@ export default async (request: Request, context: Context) => {
 };
 </code></pre>
 
-  <p>This transform Edge Function is set up to run using the <code>method=transform</code> query parameter on any URL, using this entry in the netlify.toml file:</p>
+  <p>This transform Edge Function is set up to run using the <code>method=transform</code> query parameter on any URL</p>
 
-    <pre><code>[[edge_functions]]
-  function = "transform"
-  path = "/*"</code></pre>
       <h2>See this in action</h2>
       <ul>
         <li><a href="/hello">View the original response from /hello</a> without a transform</li>
diff --git a/public/a-static-page.html b/public/a-static-page.html
new file mode 100644
index 0000000..3806c9d
--- /dev/null
+++ b/public/a-static-page.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8" />
+  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <title>Catify</title>
+  <style>
+    * {
+      font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+    }
+  </style>
+</head>
+
+<body>
+  <h1>A static page</h1>
+  <p id="location">
+    <a href="/a-static-page?catify">Catify me</a>
+  </p>
+  <img catify src="https://picsum.photos/600/800" alt="random image" width="600" height="800" />
+  <img catify src="https://picsum.photos/800/600" alt="random image" width="800" height="600" />
+</body>
+
+</html>
\ No newline at end of file
