Transform Rule redirects instead of rewrites

I set a Transform Rule and what happens now is that instead of a rewrite I get a redirect.

I don’t have any Redirect Rules in place.

I have only 1 Transform Rule in place. This is the rule:

I also have a Page Rule set for www-domain-com/ to Cache Level: Bypass

What happens now is when I load www-domain-com/?cf_test=1 in a browser it redirects to www-domain-com/?cf_test=1&timezone=my-timezone

The URL in the browser address bar should not change. Yet it does. It works as a redirect.

What is odd, though, is that if I use a Static query rewrite set to ?cf_test=1&timezone=testtest and I load www-domain-com/?cf_test=1 in a browser, it will not redirect to ?cf_test=1&timezone=testtest but will instead leave the URL in address bar as www-domain-com/?cf_test=1 and yet it will access www-domain-com/?cf_test=1&timezone=testtest - which is how it should work.

With Static query rewrite it acts as a true rewrite, with Dynamic it acts as a redirect. I need the Dynamic one to work as a rewrite because I need to pass the field to the origin server.

What am I missing?


When your Transform Rule matches the naked domain, it adds the appended query string you’ve set, but then the naked-domain-to-www redirect gets that transformed request and redirect to what you’ve seen.

You need to set any Transform Rule to match the final URL, i.e., after any expected redirects have occurred. So if you have as canonical URL you should match both https and www. as part of your TR expression, with either;

ssl and eq "" and http.request.uri eq "/cf_test=1"


http.request.full_uri eq ""

Whether you should use the first or the second (or any other variation that matches the full URL), is irrelevant, and will depend on how you manage your rules.

If I understand correctly, you imply that a 301 redirect is basically occurring at the origin server by something such as a redirect rule set in .htaccess that for example redirects the naked domain to www?

That would make sense.

However, I opened a URL in a browser that doesn’t trigger any such redirects at the origin server level as it’s “fully redirected” already.

Another thing that lifted my eyebrows is that the same expression filter:
(http.request.uri eq “/?cf_test=1”)
was used when I used a Static query rewrite and there was no redirect happening for the same URL that triggered a redirect with a Dynamic query rewrite.

That I find puzzling.

If there is a redirect set at the origin server, it would redirect with both, Danymic and Static rewrite requests, wouldn’t it?

Also, if I use an expression that matches a URL version with a naked domain and I have a redirect set at .htaccess to a www. domain version, which would trigger a redirect with any rewrite rule, how do I then set a rewrite rule to rewrite a naked domain in URL to a www. domain?

For example, I try to load in a browser, expression matches that, however, using a Dynamic query rewrite to rewrite the URL to triggers a 301 redirect at the origin server.

How do I rewrite the URL to http**s**://**www.** instead?


And that’s the expected behavior.

The rewrite is performed regardless of the Static or Dynamic type. The rediect only happens when your origin gets a request that isn’t canonical (not https or not www, for instance)

The way it works is like this:

Browser sends a request for

Your Transform Rule changes the query, but keeps the path unaltered. A TR can never change the hostname, so if the request is for, it will be passed on as you concatted in your rule

That request is passed down to Cloudflare stack of rules (normalization, Cache, Redirect, WAF etc.), then to the origin.

If you have a Redirect Rule that changes the hostname from to, the Redirect Rule will receive a request for: and will redirect it to with the chosen status code (301, 302 etc.)

This redirect would be visible in the browser. You said you don’t have such a Redirect Rule enabled, so I assumed there must be a redirect at the origin.

When you request there’s a redirect to, but since the .htaccess sees the request as already modified by the TR, it will redirect to the modified query string.

When you request, there’s no redirect by the origin, but the rewrite was already performed by the TR. The browser won’t see it, but the origin will get the modified query string.

A Transform Rule should be executed after any redirect is performed. If your canonical URL is https://www...., make the incoming requests match:

http.request.full_uri eq ""

and the Transform Rule will only apply after the last redirection is performed by the origin.


All the help provided kept pointing at the origin server redirecting. It redirects for some reason.

While the domain and protocol part of the URL didn’t seem a good candidate for the redirect since all possible redirects have cleared, it hit me.

Dynamic query rewrite of concat("cf_test=1&timezone=", has field in it which consists of Continent/City pattern. Notice the slash character?

So the rewritten query included a / in it.

Normally when we browse with URLs like that, a browser will urlencode such characters. Here CF just accessed the server with nothing urlencoded. Raw. WIth / in the query.

So the URL that is rewritten by CF to
then gets redirected to:
by the origin server.

The website on the origin server is on Wordpress.

So I assume Wordpress smooths (urlencodes) the URL and redirects to it.

So the idea now is to use .htaccess to heat Wordpress to it and urlencode with a .htacccess rewrite rule to so that the redirect won’t happen.

1 Like

Hmm… that’s not what I see here. I just tested sending to a WordPress test website (basically the default with installation with no optimization plugin) the following:

And it was received by the origin unaltered, and did not cause a redirect. I tested with Chrome, Edge and Opera.


You should check your installation to see if there’s a plugin doing that encoding, as it’s not a necessary thing to happen.

When WordPress core redirects something, it adds a header X-Redirect-By: WordPress, so you may want to check if this header is present.

I tried to rewrite/encode the query in htaccess and couldn’t get it to work.

So, I fixed the issue this way:
concat("cf_test=1&timezone=",regex_replace(, "/", "%2F"))

Whatever thing was encoding and redirecting, this stopped it.

Thanks for all the help!

1 Like

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.