Netlify Edge Function - Remove URL Parameter

I feel like I am overthinking this, but as the topic title suggests, I’m trying to remove a query parameter from a URL using an edge function.

I know this can be achieved with client-side Javascript, but I would rather do it with an edge function because I am 302 redirecting a user to this page with a Netlify Function. So the idea is they wouldn’t see the URL with a query parameter to begin with.

You’ll see in my code below, I am using the “customer” value to replace some text using the HTMLRewriter. I’d like to then remove this from the request URL, I’m assuming this would occur after I declare the customerName variable.

import { HTMLRewriter } from "https://ghuc.cc/worker-tools/html-rewriter@v0.1.0-pre.17/index.ts";

export default async (request, context) => {
  
  console.log(request);
  
  console.log(context);
  
  let url = new URL(request.url);
  
  const customerName = url.searchParams.get("customer");

  const response = await context.next();

  return (
    new HTMLRewriter()
      .on(`[data-airtable-kit="customer-name"]`, { element(element) { element.setInnerContent(customerName); }, })
      .transform(response)
  );
};

Hey @nocodebenny,

I believe you can do something like:

url.search = ''

as that should reset the query params and redirect (or rewrite) to that path?

An alternative would also be:

let url = new URL('https://google.com/?q=1')
let urlToUse = new URL(url.origin + url.pathname)

Hey @hrishikesh,

Thank you so much for getting back to me so quickly.

I’m afraid that doesn’t work :frowning:

I tried that earlier and there’s no difference. I think it may be because while the URL is being modified, that new URL isn’t being added to the response.

Hi @nocodebenny! Simon from the Edge Functions team here :wave:

You’ll need to pass the updated url object down the request chain, by passing an updated Request to context.next. This code should work:

import { HTMLRewriter } from "https://ghuc.cc/worker-tools/html-rewriter@v0.1.0-pre.17/index.ts";

export default async (request, context) => {
  
  console.log(request);
  
  console.log(context);
  
  let url = new URL(request.url);
  
  const customerName = url.searchParams.get("customer");

  const response = await context.next(new Request(url, req));

  return (
    new HTMLRewriter()
      .on(`[data-airtable-kit="customer-name"]`, { element(element) { element.setInnerContent(customerName); }, })
      .transform(response)
  );
};

Hey @skn0tt!

Thank you so much for providing that code.

I feel really stupid right now haha. I’ve tried a few different options, but I’m afraid none of them worked. You’ll see commented out in the code below, what I’ve tried so far.

If it helps at all, the request id is: 01GTKBGX65XS5AW0JQRR5JQ8HX.

import { HTMLRewriter } from "https://ghuc.cc/worker-tools/html-rewriter@v0.1.0-pre.17/index.ts";

export default async (request, context) => {
  
  let url = new URL(request.url);
  
  const customerName = url.searchParams.get("customer");
  
  //url.searchParams.delete("customer");
  //url.search = '';
  //url = new URL(url.origin + url.pathname)
  //let urlToUse = new URL(url.origin + url.pathname)

/*

I also tried this:

  url.searchParams.delete("customer");
  url.search = '';
  const newUrl = url.toString();

*/
  
  const response = await context.next(new Request(url, request));

  return (
    new HTMLRewriter()
      .on(`[data-airtable-kit="customer-name"]`, { element(element) { element.setInnerContent(customerName); }, })
      .transform(response)
  );
};

I think you need to modify the request URL before sending it to context.next(). Could you try:

let url = new URL(request.url)
url.searchParams.delete('customer')
await context.next(new Request(url, request))

Shoots, I forgot to add the .delete line to my snippet! Sorry Benny, didn’t mean to make you feel stupid :sweat_smile:

I’ve tried exactly that, @hrishikesh, but it doesn’t work :frowning_face:

My exact code is below. The most confusing piece is I am console-logging the new URL, and the log shows the URL param has been removed, but I’m not sure why it isn’t changed when passing it to context.next().

If it helps, my site ID is 3107b082-64c2-498c-8060-73858a1c62e9 and the edge function in question is the “test-checkout” one.

Ah - @skn0tt, no worries at all Simon :slight_smile:

import { HTMLRewriter } from "https://ghuc.cc/worker-tools/html-rewriter@v0.1.0-pre.17/index.ts";

export default async (request, context) => {
  
  let url = new URL(request.url);
  
  const customerName = url.searchParams.get("customer");
  
  url.searchParams.delete("customer");
  
  console.log('URL: ' + url);
  
  const response = await context.next(new Request(url, request));
  
  console.log('RESPONSE: ' + response);

  return (
    new HTMLRewriter()
      .on(`[data-airtable-kit="customer-name"]`, { element(element) { element.setInnerContent(customerName); }, })
      .transform(response)
  );
};

The searchParams.delete call mutates the local url variable, which is then used for continuing the request chain in the context.next call.
This will remove the query parameter in the request chain (so e.g. a Lambda function that’s behind the edge function wouldn’t see it), but it won’t change the URL that’s shown in the Browser. The browser will always show the URL that it used to request the page. If you want to remove the query parameter, then you’ll either have to perform a redirect (see Response.redirect), or remove it client-side. That’s a limitation in the HTTP Standard :confused:

Is that what you’re trying to solve for? I’m happy to continue helping :smiley:

Ah - fair enough, thank you so much for that explanation Simon!

Do you know if I can pass the customer name as a HTTP header instead of in a query parameter?

For context, I have a Netlify Function that serves as the “success URL” for a Stripe Checkout. It’s triggered when customers complete the checkout, so it does some work behind the scenes, and then sends them to a page - which is where I have my Netlify Edge Function running.

This is how I have the return piece of the Netlify Function structured. I tried both a 301 redirect as well as 302, but in both scenarios, the ‘X-ETS-Name’ header isn’t being set. Am I doing something wrong here?

          return {

            statusCode: 302,

            headers: {

              'Location': `XXXX`,
              'X-ETS-Name': customerName

            }

          }

Browsers won’t pass on arbitrary headers in a redirect, but you could set a cookie with the Set-Cookie header I think - the gymnastics of that depend on the origin of the URL you’re redirecting from. That could be a solution for this exact problem. If I developed this, i’d probably stick with the query parameter though - that’s far easier to debug, if anything goes wrong.

Ah - yes, that is true! Maybe I am just overcomplicating this and should stick with the query parameter haha. You are right, it is alot easier to debug and honestly, the vast majority of users wouldn’t even notice it being removed with client-side JS.

Thank you so much for all of your help, Simon!

1 Like