Changes to Redirects with query string parameters are coming

@fool Done!

1 Like

Thanks much! I pinged the dev team to take a look. Not sure if it will be a quick fix but it is now on their radar. They’ll give updates in the issue as things, er, develop!

So I am probably going about this wrong, but how do I redirect and NOT preserve the query params?

Here is a demo site I created that only has the following redirects, and no javascript whatsoever.

# Pagination
# redirect page 1 to route with no page in URL
/*    page=1   /:splat   301!
# Redirect queryparam to param
/*    page=:page   /:splat/:page   301!

So what I want to have happen is redirect to

And redirect to

What happens with my setup though, is the ?page=1 redirects to itself infinitely because the query params are preserved. And ?page=2 redirects to /2?page=2 which redirects to /2/2?page=2 and so on, infinitely getting deeper in the infinite redirect.

Is there a way to say redirect but do NOT preserve the query params?

Thanks for any help or insight on how I can go about this.

1 Like

hi there, before we dig in, did you see this brand new guide on debugging redirects?

I strongly suggest you give it a thorough read through and see if this fixes your problem:

if not, please post again, and we’ll try and troubleshoot.

Thanks for the reply.

I have read that article, and been through your docs on query params redirects. I may be missing something but I still don’t see an answer to my question.

How can I make these redirects NOT preserve query params?

/* page=1 /:splat 301!
/* page=:page /:splat/:page 301!

I think this rule used to work as intended, but this change to preserve query params you have just rolled out makes it infinitely redirect. I could be wrong though.

I have no other redirects. There is no application code, I created this application to debug these 2 rules in isolation.

If the query param were to not be preserved, the condition page=1 would no longer match after the first redirect and it would not redirect again.

Thanks for the help

Or is there a better way to achieve the same result without the infinite redirect?

I want any URL that has ?page=1 to redirect to the same URL but without ?page=1


Any URL that has ?page={any other value} to redirect to the same URL but with /:page at the end and the page query string removed.


A post was split to a new topic: Query string cached when redirecting

Hey Rob! This is a very new change which I too am still familiarising with.

I’ve set up a repro and I can also observe this. I’m not seeing a quick win so I’ll raise this internally to see what the wider team suggest. Thanks for bearing with us!

@annejan, are you saying that the content on the page with the query string is being cached by our CDN, or is this explicitly an issue because we now pass the query string parameter to the result (similar to the report above)?

@robmsw et al,

I’ve filed an issue for our team to investigate. You can break the redirect loop, for now, by including a dummy query string param. @robmsw, your redirects therefore could look similar to this:

/*    page=1   /:splat?no-query-string   301!
/*    page=:page   /:splat/:page?no-query-string   301!  

I’ve created a demo showcasing this for you here:

Thanks for bringing this to our attention!

@Scott thanks for the help, adding that parameter in does break the loop and having the null=null in the url should be fine for my current use case. Thanks!

1 Like

I am attempting to configure a simple redirect which takes path parameters and exposes them as querystrings.

The configuration looks as follows and by my understanding should work

    from = "/api/meta/:symbol/:tokenId"
    to = "/.netlify/functions/meta?symbol=:symbol&tokenId=:tokenId"
    force = true
    status = 200

However when hitting the endpoint /api/meta/symbol/123 no querystrings are received by the function.
If I instead use /api/meta/symbol/123?symbol=sym&tokenId=123 they are.

Why does the redirect rule not correctly package the querystring values?

Hi @eddyoc,

To pass query strings like this, you’d need a 301 redirect. For example, you can check this out: Add any path to it like: and you’d see the query string received by the function. It’s just doing JSON.stringify(event.queryStringParameters).

If you don’t wish to expose your function endpoint, you’d have to do another 301 back to the page that called it, but you probably won’t be able to return a JSON response this way. The recommended way to use query parameters with functions is the way you have already mentioned.

You can just do /api/meta/?symbol=sym&tokenId=123 and the query string will be received by the meta function.

I had this simple rule

/* fbclid=:fbclid /:splat 301!

to manage the mess that facebook adds to the url, but now it is no longer working in some mobile browsers ( firefox, chrome) although it works in brave.


There is a workaround for this to work again as expected?

Hi @samarul,

Did you try this:

Hi @hrishikesh,

Yes, I tried this, but this is not what I am looking for as it adds something to the URL and thus my analytics are changed. So I have and for the same URL

Hi @samarul,

Unfortunately, that’s the only way for now as we can’t make an informed decision on whether a user wants to remove the strings or not.

I’ve suggested what I think might be possible (add a configuration option to the TOML file), but waiting for the developers’ comments on it.

Even with that, I don’t know if/when this will change, so till then, you’d have to work with the extra string.

Any updates on how to remove the unwanted query strings in a “non-hacky” way?

I’m trying to redirect from to in my netlify.toml file

My approach:

  from = "/*"
  to = "/:splat/?success"
  query = {oauth_token = ":token", oauth_verifier = ":verifier"}
  force = true

This kinds works…it results in But how can I remove the ?success?

1 Like

There’s no other way (except JavaScript) at the moment.

It looks like this was implemented not just for configured redirects, but ALL 301 and 302 redirects, even responses from serverless functions? Can you confirm?

If so, I’m sorry but this is a poor implementation. When implementing an oAuth flow, the 3rd party authorization servers issues a 302 redirect back to our serverless function with code, state etc as query parameters. Those parameters get validated, and we redirect the user to the initial page they were trying to reach, or a default after-login page.

But we can’t seem to be getting rid of those oAuth query params! The end URL is full of oAuth garbage. Worse, the behavior is different in production vs dev environment. This doesn’t happen when using Netlify dev.

Is there truly no way to turn off this quirky behavior? This is nuts.

For anyone struggling with this issue, here’s an edge function that fixes the problem. It detects the Netlify query string redirect behavior by comparing incoming request and outgoing response query params on 301s and 302s, and strips the query string the location header value if the parameters are identical.

We didn’t want this behavior at all, so this works for us, but you might want to add a filter to this logic to conditionally apply this behavior based on specific paths.

Finally, beware that you will only be able to test this behavior when running on Netlify CDN. Dev environment does not exhibit the behavior.

Netlify automatically appends origin query parameters to 
all redirected URLs if a query string is not present in the redirected URL
This handler fixes it by removing the query string from the redirected URL if the parameters are identical


export default async (request, context) => {
        const url = new URL(request.url);
        if(! return;

        console.log(`Incoming URL: ${request.url}`);

        let res = await;

            const location = res.headers.get('location'),
                redirectedQueryString = location?.slice(location.indexOf('?'));

            console.log(`Redirected URL: ${location}`);


                const params = new URLSearchParams(redirectedQueryString);

                // Compare incoming and outgoing query parameters
                let identical = true;
                for(const [key, value] of url.searchParams.entries()){
                    if(params.get(key) !== value){
                        console.log(`Incoming and redirected query params are different: ${key}=${value} vs ${params.get(key)}`);
                        identical = false;

                    console.log("Found identical query strings, stripping the redirect URL query string");
                    res.headers.set('location', location.split('?')[0]);
                    return res;
                    console.log("Incoming and redirected query params are different, not altering location");