The 3 AM Page

It’s October 2nd, and AI quiz generation in Trivista is completely broken. Users are getting “internal error” messages. The logs show this:

Error: Perplexity API error: 403
"We have detected unusual activity coming from your IP address and blocked your request.
We block VPNs to prevent spam and abuse."

The problem: I’m not using a VPN. I’m calling Perplexity’s API from a Firebase Cloud Function running in Google Cloud’s us-central1 datacenter.

Cloudflare, which sits in front of Perplexity’s API, decided that Google Cloud’s IP addresses look suspicious. False positive at scale.

Why This Matters

This isn’t a Perplexity problem. It’s a fundamental tension in cloud infrastructure:

  • Anti-bot systems need to be aggressive to stop abuse
  • Datacenter IPs get shared across thousands of customers
  • Cloudflare’s heuristics can’t always distinguish legitimate cloud services from malicious bots
  • Your production app becomes collateral damage

The Perplexity API terms of service explicitly allow this use case. The technical layer below it doesn’t care.

Not the crawler controversy

This is unrelated to the August 2025 news about Perplexity’s web crawler. That was about Perplexity’s bots scraping websites. This is about Cloudflare blocking legitimate API requests to Perplexity from cloud infrastructure.

The Investigation

First thought: maybe I violated something. Checked the Perplexity API TOS. My use case (generating quiz questions) is explicitly allowed. No rate limit violations. Nothing unusual in my request patterns.

The issue wasn’t policy. It was infrastructure. Cloudflare’s anti-bot detection flagged Firebase Functions’ outbound IPs as “VPN-like” traffic. Legitimate request, wrong network reputation.

This left me with two options:

  • Contact support and hope it gets resolved quickly (uncertain timeline for production outage)
  • Route through something that doesn’t trigger bot detection

The Solution: OpenRouter

OpenRouter is an API aggregator that provides unified access to 400+ AI models. Key features for this use case:

  • Single API endpoint for multiple providers (Perplexity, OpenAI, Anthropic, etc.)
  • Built-in fallback: specify model priority, automatic failover if one fails
  • BYOK support: bring your own API keys, use your prepaid credits instead of buying through OpenRouter
  • No markup pricing: first 1M requests/month are free, then 5% fee

The workflow becomes:

Your App → OpenRouter → Perplexity API (or fallback to OpenAI)

Testing: Perplexity vs OpenAI

Before deploying, I tested both providers through OpenRouter using the topic “k-pop demon hunters” (a recent Netflix movie). This is a good test for web search quality, since it requires current knowledge.

Perplexity Sonar Results

  • Found the actual Netflix movie and generated specific trivia
  • Questions: “What is the name of the K-pop girl group that hunts demons?”, “What does ‘Gwi-Ma’ combine in Korean?”
  • Time: 6.4 seconds

OpenAI GPT-5-mini:online Results

  • Generic questions about K-pop + demon hunter themes
  • Questions: “Which Korean folk creature appears in K-pop demon-hunter stories?”, “Which musical element evokes tension?”
  • Time: 38.2 seconds

Perplexity’s web search found the specific content. OpenAI’s web search gave generic folklore answers. Winner: Perplexity via OpenRouter.

Though it’s worth noting: even a slow fallback is better than no service. If Perplexity gets blocked again, I’d rather serve generic questions in 38 seconds than fail completely.

I’m now using this same infrastructure for Trivista, which generates personalized trivia games. Being able to route between providers without code changes is valuable when you’re dealing with current events and need reliable web search.

What This Doesn’t Solve

Let’s be clear about limitations:

  • You’re still dependent on underlying providers. If Perplexity has an outage, OpenRouter can’t magic up uptime. The fallback helps, but you’re trading one dependency for multiple.

  • Adds an indirection layer. Every request goes through OpenRouter’s infrastructure. That’s another potential point of failure, another network hop, another service to monitor.

  • Vendor lock-in, different flavor. Moving from “locked into Perplexity” to “locked into OpenRouter’s API format” is still lock-in. The abstraction helps, but you’re betting on OpenRouter staying around.

  • Testing complexity increases. Now you need to test: Perplexity via OpenRouter, OpenAI via OpenRouter, fallback behavior, BYOK configuration. More surface area for bugs.

  • Cost tracking gets harder. When requests automatically fail over between providers with different pricing, your cost per request becomes variable. Budget accordingly.

Lessons Learned

  • Cloud platform IPs can be blocked. Datacenter IP reputation is shared across all customers. What works on your laptop might fail in production for reasons completely outside your control.

  • Direct API integration is fragile. One provider, one endpoint, one set of network paths. Any layer can fail. Cloudflare deciding you look like a bot, DDoS protection triggering, routing changes, all can break you.

  • Provider abstraction adds resilience. Not because it prevents failures, but because it gives you options when they happen. Automatic failover beats manual code changes at 3 AM.

  • Performance testing matters. The 4x speed difference (6s vs 38s) wasn’t obvious until I tested. Assumptions about “GPT must be better” or “they’re probably similar” don’t survive real workloads.

  • Web search quality varies significantly. Perplexity found specific, current content (the actual Netflix movie). OpenAI gave generic answers. For trivia generation, that difference matters.

The Deployment

The migration took about 2 hours. Most of that was setting up structured outputs with JSON schema validation and running a battery of tests against the previous setup. The actual code change was minimal - swap the endpoint, update the secret, deploy.

What struck me: I’m still using the same Perplexity Sonar model with the same performance characteristics. The only difference is the routing path. Users see no change. Cloudflare doesn’t flag the new requests. The problem wasn’t my application or my API usage - it was just network-layer reputation scoring.

Try It Yourself

If you’re building on AI APIs, consider:

  • Can Cloudflare block you? If you’re calling APIs from cloud functions, probably yes
  • What’s your fallback? Do you have a backup provider that you can switch to quickly?
  • How much does downtime cost? For me, broken quiz generation = broken core feature

OpenRouter’s docs are solid if you want to explore this approach. The BYOK setup takes about 5 minutes.

The real lesson

Infrastructure dependencies go deeper than your API contract. Sometimes the network layer makes decisions for you.