●SANDBOX — Claude Managed Agents can now run in your own sandbox and connect to private MCP servers (self-hosted beta, MCP tunnels in preview)●PLATFORM — The Claude Developer Platform adds new code execution, web search, and web fetch tools, exposing a 90-second per-cell limit●CONTEXT — response_inclusion trims consumed result blocks to save context in agentic workflows●MCP — Enterprise-managed MCP connectors (Okta) continue: zero-touch access across Claude, Claude Code, and Cowork (Team/Enterprise beta)●CODE — Claude Code adds /cd, a post-session hook, and a safe mode while tightening MCP policy enforcement●MODEL — Opus 4.8, Sonnet 4.6, and Haiku 4.5 lead the lineup; Fable 5 is available from Claude Code●SANDBOX — Claude Managed Agents can now run in your own sandbox and connect to private MCP servers (self-hosted beta, MCP tunnels in preview)●PLATFORM — The Claude Developer Platform adds new code execution, web search, and web fetch tools, exposing a 90-second per-cell limit●CONTEXT — response_inclusion trims consumed result blocks to save context in agentic workflows●MCP — Enterprise-managed MCP connectors (Okta) continue: zero-touch access across Claude, Claude Code, and Cowork (Team/Enterprise beta)●CODE — Claude Code adds /cd, a post-session hook, and a safe mode while tightening MCP policy enforcement●MODEL — Opus 4.8, Sonnet 4.6, and Haiku 4.5 lead the lineup; Fable 5 is available from Claude Code
Reserving Priority Capacity for User Traffic with service_tier
If you pay for Priority Tier but your user-facing responses still slow down at peak, the culprit is often your own background jobs eating the priority pool. Here is how to read service_tier, prove the contention, and isolate background work.
A while after I started paying for Priority Tier, I noticed something odd. During the late-afternoon hours when user questions spike, the same prompt against the same model would respond noticeably slower than usual. Nothing in my code had changed. Yet only at peak, I was waiting.
It took a detour to find the cause. In short, the automated jobs I run in the background were competing for the very same priority pool as my user-facing requests. I had not understood how the service_tier request parameter actually behaves, and that gap surfaced directly as latency. As an indie developer running the scheduled work for the four Dolice Labs sites and the question-answering traffic through a single API key, this kind of contention is very easy to create.
What actually slows down user responses at peak
Priority Tier is a commitment that reserves a per-minute throughput of input and output tokens. Within that reserved range, your requests are served preferentially even under load, and latency stays consistent. The catch is that the pool is not infinite — it is exactly as large as you committed to.
The default value of service_tier is auto. An auto request uses the priority pool if there is room, and falls back to the standard pool otherwise. That sounds smart, but here is the trap: your background jobs also try to consume the priority pool as auto unless you say otherwise.
In my case, the afternoon peak was exactly when "more user questions" and "the article-generation batch I had scheduled for the evening" overlapped. The background jobs filled the priority pool first, pushing the user-facing requests out into the standard pool. That is why they slowed down.
What service_tier decides — auto versus standard_only
Here are the values service_tier can take and what each one means.
Value
Behavior
Good fit for
auto (default)
Use the priority pool if available, otherwise fall back to standard
User-facing synchronous requests where latency matters
standard_only
Never use the priority pool; always serve from standard
Background and scheduled jobs that can tolerate some delay
The key is to read standard_only as "do not let this consume the priority pool" rather than "make this slow." When the standard pool has room, a standard_only request still comes back quickly. The goal is not to slow anything down — it is to keep your finite, committed priority capacity free for the traffic you actually want to protect.
For work that is fine to return asynchronously within 24 hours, the first choice is the Batch tier (roughly 50% cheaper) instead. I cover that in the Claude API Messages Batches async processing guide. This article is about the middle ground that cannot go to Batch: work you want to receive synchronously, but do not want to prioritize as highly as user traffic.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Diagnose why only your user-facing Claude API responses slow down at peak by understanding how service_tier auto and standard_only behave
✦Log usage.service_tier on every call so you can verify after the fact whether each request was served by the priority pool or the standard pool
✦Pin nightly automated jobs to standard_only and keep the priority capacity you pay for reserved for user-facing traffic
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
Specifying it is simple — add one line to the Messages API request body. Here is the Python example.
import anthropicclient = anthropic.Anthropic()# Background job: do not consume the priority poolmessage = client.messages.create( model="claude-haiku-4-5-20251001", max_tokens=1024, service_tier="standard_only", # keep priority capacity free messages=[{"role": "user", "content": "Summarize this article in 3 sentences"}],)# The tier that actually served the request shows up in usageprint(message.usage.service_tier) # e.g. "standard"
The same idea applies in TypeScript with the official SDK.
import Anthropic from "@anthropic-ai/sdk";const client = new Anthropic();const message = await client.messages.create({ model: "claude-haiku-4-5-20251001", max_tokens: 1024, service_tier: "standard_only", // pin background jobs to standard messages: [{ role: "user", content: "Summarize this article in 3 sentences" }],});console.log(message.usage.service_tier); // "standard"
For the user-facing synchronous path, either leave it unset (which means auto) or write service_tier: "auto" explicitly. Being explicit makes the intent obvious when you reread the code: this path is allowed to use the priority pool.
Confirm the reality with usage.service_tier
What actually moved the needle first was observation, not configuration. Whether an auto request was really served by the priority pool or fell back to standard is invisible unless you read usage.service_tier on the response. Because I was not recording it, I misread the cause of the slowdown for a long time.
So I wrapped every call in a thin helper that always logs which pool served it.
import loggingimport anthropiclogger = logging.getLogger("claude")client = anthropic.Anthropic()def call(messages, *, tier="auto", label="unknown", **kwargs): """Set service_tier explicitly and record the pool actually used.""" msg = client.messages.create( model="claude-haiku-4-5-20251001", max_tokens=1024, service_tier=tier, messages=messages, **kwargs, ) served = msg.usage.service_tier # "priority" / "standard" / "batch" # Make the gap between requested and served pool auditable later logger.info("tier_request=%s tier_served=%s label=%s in=%d out=%d", tier, served, label, msg.usage.input_tokens, msg.usage.output_tokens) return msg
Aggregating a single day of this log shows, as a number, how many requests at peak were tier_request=auto but tier_served=standard. In my environment, nearly 30% of auto requests were pushed out of the priority pool during the busiest hour. Once that lined up with the latency I was feeling, the cause was finally settled.
Pin background jobs to standard_only to protect the pool
Once observation confirms the contention, the fix is straightforward: send every non-user-facing call as standard_only. With the wrapper above, you only pass a different tier at each call site.
# Synchronous user request: allowed to use the priority poolreply = call(user_messages, tier="auto", label="user_chat")# Nightly / scheduled job: standard_only to preserve priority capacitysummary = call(batch_messages, tier="standard_only", label="nightly_summary")
When rolling this into production, here is the order I followed.
Add observation only. Leave service_tier unchanged and just log usage.service_tier for a day or two.
Check how much auto traffic falls back to standard at peak, and confirm the contention is real.
Switch background-job calls to standard_only one at a time. Touch the user-facing path last.
After each switch, confirm in the logs that the tier_served=priority rate for user-facing auto requests improved.
The point is not to flip everything at once. Convert the background jobs one by one, watching the priority-hit rate for user traffic recover each time. As a bonus, you learn which job was eating the most priority capacity.
Which workload belongs in which pool
The deciding axis is a single question: is a user waiting on this right now? I sort it out like this.
Workload
Recommended pool
Why
User-facing synchronous responses (chat, support)
auto
Latency drives experience, so use the priority pool
Internal synchronous work (admin-side helper generation)
standard_only
Delay is acceptable; keep priority capacity reserved
Async work fine to return within 24 hours
Batch tier
Roughly 50% cheaper, and pressures neither pool
Tuning cost and latency per stage by varying the model or reasoning effort pairs well with the per-stage effort parameter article. service_tier decides which pool serves the request, while effort decides how hard the model thinks, so the two are orthogonal. Combined, you can assign user-facing traffic to the priority pool with enough effort, and background jobs to the standard pool with modest effort.
Common pitfalls
Expecting too much from standard_only without a Priority Tier commitment. If you have not committed to priority capacity, both auto and standard_only are effectively served by standard, so switching changes nothing. This setting only matters when you hold a finite priority pool and want to control how it is allocated. If you have not, moving async work to Batch has a far larger effect.
Reading standard_only as the "always slow" pool. When the standard pool has room, it returns quickly. Treat standard_only not as sacrificing latency, but as opting out of the competition for the priority pool.
Leaving everything on auto without watching usage.service_tier. Without observation, you cannot even notice the priority pool is exhausted. At minimum, log the pair of requested and served pool so peak behavior is traceable as a number.
Confusing peak latency with 529 errors. Being pushed out of the priority pool into standard is normal behavior and does not raise an error. Separately, when the standard pool itself gets congested, you may see 529. Handling congestion itself is a different topic, covered in handling Claude API 529 overloaded errors. service_tier is about pool allocation; 529 handling is about persistence under congestion.
One step to take first
Before changing any code, start by adding a single log line for usage.service_tier. The moment the gap between the pool you requested and the pool you were served becomes a number, where to direct your priority capacity decides itself. I misread the cause myself until I added that observation, so I would recommend measuring first.
Share
Thank You for Reading
Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.