Skip to content

Troubleshooting

This page covers the issues we see most often when customers set up Turbulence. Most of them fall into a few categories: DNS problems, cache problems, and HTML oddities. If you don’t see your problem here, the Verifying It Works page has a checklist of things to check, and the support team is happy to help with anything else.

After you add the TXT record, the dashboard keeps showing Pending Verification.

The most common cause is DNS propagation delay. Most records propagate within a few minutes, but it can take up to an hour in some cases. The domain setup page polls Cloudflare for status automatically every 5 seconds — you don’t need to refresh or click anything.

If verification still fails after an hour (or the badge shows Verification Failed):

  • Check the record exists. From a terminal, run dig TXT against the exact Name value from your dashboard’s Verification TXT Record section (often something like _cf-customhostname.yourdomain.com). The output should show a TXT record matching the Value shown in the dashboard. If nothing comes back, the record isn’t in your DNS yet.
  • Check the name field. Your provider might expect just the subdomain portion and add the rest of the domain automatically, or it might expect the full hostname. Look at how other records in your DNS are formatted and match that.
  • Check the value field. Some providers require the value to be wrapped in double quotes. If your provider’s docs aren’t clear, try with and without quotes and see which one sticks.
  • Check for duplicate records. If you have two TXT records at the same name, the wrong one might be served. Remove duplicates.
  • Check the cache TTL. If you have an old TXT record at the same name with a long TTL, it might be served by intermediate resolvers even after you update it. Either wait for the TTL to expire, or remove the old record.

The CNAME doesn’t seem to be doing anything

Section titled “The CNAME doesn’t seem to be doing anything”

You added the CNAME and the site still loads from your original server.

  • Confirm the CNAME is in place. Run dig CNAME www.yourdomain.com and check that the response is optimize.picperf.io (or an IP, if your provider flattens CNAMEs at the apex). If nothing comes back, the record isn’t resolving.
  • Check you’re querying the right name. A CNAME on www doesn’t affect yourdomain.com (the root), and vice versa. If you added the CNAME on one but you’re testing the other, nothing happens.
  • Browser cache. A hard refresh (Cmd/Ctrl + Shift + R) clears the browser’s cache. The browser may be holding onto the old DNS or the old response.
  • Local DNS cache. Your operating system caches DNS too. On macOS, sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder will clear it. On Windows, ipconfig /flushdns. On Linux, the procedure depends on the distribution.
  • You’re behind a CDN. If your site is behind another CDN (Cloudflare, Fastly, etc.) on a different hostname, traffic may still flow through that CDN before reaching PicPerf. Either point the CNAME at Turbulence from that CDN, or terminate the CDN at a different hostname.

I use the root domain, and my provider won’t let me add a CNAME

Section titled “I use the root domain, and my provider won’t let me add a CNAME”

A few DNS providers don’t support CNAME records at the root (apex) of a domain. The DNS spec says CNAMEs can’t coexist with other records at the same name, and most root domains have other records (NS, MX, etc.) that conflict.

Most modern providers have a workaround:

  • Cloudflare: supports CNAME flattening at the apex automatically. Just add the CNAME and Cloudflare resolves it behind the scenes.
  • AWS Route 53: use an “alias” record instead of a CNAME. The effect is the same.
  • GoDaddy, Namecheap, Google Domains, Squarespace Domains, Porkbun, and most others: look for an “ALIAS”, “ANAME”, or “CNAME at apex” record type. The label varies by provider, but the effect is what you want.

If your provider truly doesn’t support any apex-CNAME workaround, the practical solution is to use a subdomain (www or similar) as your primary hostname, and 301-redirect the root to it.

The site works, but some pages are missing

Section titled “The site works, but some pages are missing”

Turbulence optimizes the HTML response. If a “page” is actually an API endpoint, a JSON file, a .pdf, an image, a video, or anything else with a non-HTML Content-Type, it will pass through Turbulence unchanged. So if /api/data.json returns JSON, you’ll still get JSON back — Turbulence just doesn’t try to optimize it.

This is by design. If you have a piece of your site that you expected to be optimized and isn’t, the first question is: what’s its Content-Type?

I updated a page, but visitors still see the old version

Section titled “I updated a page, but visitors still see the old version”

By default, the cache is “fresh” for 1 hour (3600 seconds) — configurable per domain under Settings (range: 60 seconds to 24 hours). Within that window, Turbulence returns the cached version without re-fetching from your origin. After the TTL elapses, the cache goes “stale” and Turbulence starts revalidating in the background — but visitors still get the cached version immediately while revalidation runs, for up to 7 days (the max-stale age).

For most updates, waiting for the configured TTL is fine. If you need to confirm what a fresh fetch would produce:

  • Append ?pp_verify=1 to the URL. This bypasses the cache for that single request and runs the full pipeline synchronously. It does not write the result back to the cache, so other visitors are unaffected.
  • Lower the cache TTL in Settings. This affects future cache cycles, not entries already stored.
  • Contact support if you need immediate cache invalidation across your site — there is currently no per-URL or per-domain purge button in the dashboard.

A MISS on the first request to a URL is expected. But if you keep seeing MISS on repeated visits to the same URL, something is generating a different cache key each time:

  • The query string is changing. ?utm_source=, ?fbclid=, and other tracking parameters make each visit a unique URL from a caching perspective. Turbulence caches by full URL. If your analytics or ad platform is appending unique parameters, you’ll churn the cache.
  • The page is doing client-side URL changes. Single-page apps that update the URL via history.pushState don’t trigger Turbulence requests — Turbulence only sees the initial page load. But if you’re seeing MISS on a static HTML page, check the request URL carefully.
  • The cache is being bypassed intentionally. Check the request URL for ?pp_verify=1 (bypasses cache for debugging) or ?bust=1 (bypasses cache in the worker’s development environment only).

If a visitor reports broken HTML, the first thing to check is whether the cached version is the problem or the origin is. You can force a fresh fetch with ?pp_verify=1 (which bypasses the cache and runs the pipeline inline) and see if the response is correct:

Terminal window
curl -s "https://www.yourdomain.com/about/?pp_verify=1" | head -100

If the pp_verify=1 response is correct but the regular response is broken, the edge cache likely has a stale or partially-optimized entry. Wait for revalidation to complete, lower the cache TTL in Settings, or contact support for cache invalidation.

If the pp_verify=1 response is also broken, the issue is somewhere in the transformation pipeline. Open a support ticket with:

  • The URL
  • A description of what’s broken (missing element, wrong attribute, weird characters, etc.)
  • A curl -s "...url...?pp_verify=1" of the broken output

The most common cause of “Turbulence breaks my page” issues is a parser edge case in the HTML — for example, a <script> block containing literal < or > characters in a string, or an <img> tag with attributes the rewriter doesn’t recognize. These are fixable, and the more detail you can share, the faster we can get them resolved.

The page is slow on the first request, fast after

Section titled “The page is slow on the first request, fast after”

The first request to a URL fetches from your origin and runs the full transformation pipeline inline, which is slower than serving from the edge cache. Subsequent requests are served from cache and are very fast.

This is expected behavior, not a bug. If you want to warm the cache for a URL before visitors see it, options include:

  • Visit the URL yourself first to populate the cache.
  • Use a monitoring/uptime tool that pings the URL periodically. Each ping fills the cache for some time.
  • Open a support ticket to discuss a cache-warming option for larger sites.

A specific image isn’t going through PicPerf

Section titled “A specific image isn’t going through PicPerf”

If most images on a page are being routed through PicPerf, but one isn’t, check:

  • The image’s URL host. If the URL is on a known CDN (Cloudinary, Imgix, Shopify CDN, Fastly, etc.), Turbulence leaves it alone. This is intentional — those CDNs are already doing their own optimization.
  • The image is in a <noscript> block. Turbulence doesn’t process content inside <noscript> (which the browser wouldn’t render anyway).
  • The image is added by JavaScript after page load. Turbulence operates on the HTML response, not on DOM mutations. If a script adds <img> elements to the page after the HTML is parsed, those URLs aren’t part of the static transformation.

A specific script is being modified when it shouldn’t be

Section titled “A specific script is being modified when it shouldn’t be”

Turbulence adds async to known-safe third-party scripts (analytics, ad pixels, tag managers). The list is broad but not universal. If you have a third-party script that needs to remain render-blocking — for example, a consent management platform that has to run before any other scripts — and it’s on the safe-script list, you have two options:

  • Set async or defer on the script yourself. Turbulence respects existing async and defer attributes and won’t override them. But note that “I have an async already” means the script will be loaded asynchronously — if you need it to remain render-blocking, defer may not be a substitute.
  • Contact support to have the script removed from the safe-list if you have a legitimate reason.

My Google Fonts or Typekit fonts aren’t being self-hosted

Section titled “My Google Fonts or Typekit fonts aren’t being self-hosted”

Google Fonts and Typekit self-hosting both run in the fonts step, which is marked slow and completes in the background on the first visit. The first request to a page with fonts.googleapis.com or use.typekit.net will still see the original <link rel="stylesheet"> in the HTML. Reload the page (or wait for cache revalidation) and you should see it replaced with <!-- ⚡ INJECTED BY PICPERF ⚡ --> and an inline <style> block.

If self-hosting never kicks in after several reloads:

  • Confirm the page references a supported provider. Look for fonts.googleapis.com, use.typekit.net, or use.typekit.com in the source. If neither is present, there’s nothing for the fonts step to process.
  • Check the response headers. X-PicPerf-Steps should include fonts once self-hosting has completed for a URL. On a cache miss you may see X-PicPerf-Pipeline-Stage: partial while the step is still running.
  • Try ?pp_verify=1. This forces the full pipeline synchronously, including the slow steps, so you can confirm the self-hosted output without cache timing variance.

My site is in a different language and the page looks “off”

Section titled “My site is in a different language and the page looks “off””

Turbulence’s transformations are language-agnostic. It rewrites URLs, attributes, and resource references — not content. If your page is rendering with broken characters, missing elements, or wrong content, that’s a problem with your origin’s HTML, not with Turbulence.

That said, one place where language can matter: if your page uses the lang attribute on <html>, Turbulence preserves it. If you’re seeing issues with right-to-left text rendering, that’s also an attribute on the HTML Turbulence leaves alone.

A few common reasons:

  • You’re testing a page that was already well-optimized. If your origin already serves modern image formats, self-hosts its fonts, and uses async loading for third-party scripts, Turbulence has less to do. The free analysis report will show you exactly which steps did and didn’t fire.
  • You’re testing a non-HTML response. PageSpeed Insights scores HTML pages. If you’re running PSI on an API endpoint or a JSON URL, the score doesn’t reflect what Turbulence can do.
  • You’re comparing the wrong things. Run PSI on the same URL twice — once with the DNS pointed at Turbulence, and once with the DNS pointed at your origin (or in an incognito window with the cache cleared). The “before” should be the unoptimized version, and the “after” should be the Turbulence version.
  • Your origin is the bottleneck. If the page is slow because of expensive server-side rendering or a slow database query, Turbulence can’t speed that up. The HTML transformation happens after your origin responds.

This is normal and expected. PageSpeed Insights runs a mobile simulation by default (slower CPU, throttled network, smaller viewport), so the score will be lower than the desktop version. The improvement from Turbulence should still be visible on both — the absolute scores just differ.

If none of the above covers your situation, open a support ticket with:

  • The URL that’s misbehaving
  • A description of what you’re seeing versus what you expected
  • A curl -s "...url...?pp_verify=1" output (if applicable)
  • A note on when the issue started

The more detail you can share, the faster we can diagnose.