Skip to main content

YouTube API Quota

Lumio uses InnerTube — YouTube's own internal API — as the primary transport for chat reception and broadcast discovery. InnerTube costs 0 Data API quota. The YouTube Data API v3 is only used for one-time liveChatId resolution, chat sending, moderation, and channel enrichment.

The YouTube Data API v3 enforces a daily quota of 10,000 units per project (resets at midnight Pacific Time).

Transport Overview

TransportPurposeQuota Cost
InnerTube (primary)Chat polling, broadcast discovery, badge/emote enrichment, statistics (likes, views)0
gRPC streamList (fallback 1)Chat reception via persistent server-push connection0
REST Data API v3 (fallback 2)Chat polling when InnerTube and gRPC both fail5 units per poll

Fallback cascade: InnerTube → gRPC (if grpc_fallback_enabled) → REST (if rest_fallback_enabled). Each transition triggers after 3 consecutive failures within 60 seconds. Both fallbacks are disabled by default.

Quota Cost Reference

Official costs per YouTube Data API v3 operation:

OperationEndpointCost (units)
List broadcastsliveBroadcasts.list1
List chat messagesliveChatMessages.list5
Send chat messageliveChatMessages.insert200
List channelschannels.list1
List videosvideos.list1
Searchsearch.list100
List subscriptionssubscriptions.list1
Transition broadcastliveBroadcasts.transition50

The default daily limit is 10,000 units. Higher limits require passing Google's Quota and Compliance Audit.

Quota-Free Operations (InnerTube + gRPC)

These operations cost 0 Data API quota:

OperationTransportSource
Chat pollingInnerTube get_live_chatcrates/lo-youtube-api/src/innertube/mod.rs
Broadcast discoveryInnerTube browsecrates/lo-youtube-api/src/innertube/browse.rs
Badge + emote enrichmentInnerTube (inline in chat responses)crates/lo-youtube-api/src/innertube/parser.rs
Like count + view countInnerTube updated_metadata / playercrates/lo-youtube-api/src/innertube/browse.rs
Chat streaming (fallback)gRPC liveChatMessages.streamListcrates/lo-youtube-api/src/streaming.rs

InnerTube is unauthenticated — no OAuth token required for chat reception.

Quota-Consuming Operations (Data API v3)

liveChatId Resolution

AspectDetails
EndpointliveBroadcasts.list
Cost5 units
FrequencyOnce per broadcast, cached in channel_status table
Sourcecrates/lo-youtube-api/src/innertube/browse.rs resolve_broadcast_chat_ids()

InnerTube browse returns broadcast IDs but not liveChatId. For newly discovered broadcasts, liveChatId is resolved once via Data API and cached permanently. This call runs regardless of the rest_fallback_enabled setting.

Chat Sending + Moderation

OperationEndpointCostFrequency
Send chat messageliveChatMessages.insert200Per message sent
Ban / timeout userliveChat/bans200Per action
Delete messageliveChatMessages.delete200Per action

These use the user's login OAuth connection (get_provider_token("google")), not the channel connection.

Channel Info Lookup

AspectDetails
Endpointchannels.list
Cost1 unit
Sourceapps/api/src/routes/connections.rs fetch_channel_info()
TriggerOnce per YouTube channel connection (OAuth callback)
Daily UnitsNegligible (< 10)

REST Fallback (Disabled by Default)

Only active when both rest_fallback_enabled = true and InnerTube + gRPC have failed:

OperationEndpointCostInterval
Broadcast discoveryliveBroadcasts.list1Every 60 s
Chat pollingliveChatMessages.list5~10 s active / 30 s idle
CallerFileDaily Units (per channel, worst case)
YouTube Worker (broadcast poll)apps/api/src/workers/youtube.rs1,440
YouTube Worker (chat poll)apps/api/src/workers/youtube.rsup to 43,200

Configuration

[youtube]
# Enable gRPC streamList as first fallback when InnerTube fails
# ENV: LUMIO__YOUTUBE__GRPC_FALLBACK_ENABLED
grpc_fallback_enabled = false # default

# Enable REST polling as last resort when InnerTube + gRPC both fail
# Also gates Data API broadcast discovery fallback
# ENV: LUMIO__YOUTUBE__REST_FALLBACK_ENABLED
rest_fallback_enabled = false # default

Daily Quota Calculator

Default Mode (InnerTube Only)

With both fallbacks disabled (default), quota consumption is minimal:

Per active channel (stream is live):

ComponentQuota per callCallsQuota
InnerTube chat polling0~28,800/day (3 s interval)0
InnerTube broadcast discovery01,440/day (60 s interval)0
InnerTube statistics01,440/day (60 s interval)0
liveChatId resolution51 per broadcast (cached)5
Total5

Per idle channel (no stream):

ComponentQuota per callCallsQuota
InnerTube broadcast discovery01,440/day0
Total0

Example: 1 Channel, 8h Stream (Default InnerTube Mode)

Idle hours (16h): 0 units
Stream hours (8h): 0 units
liveChatId resolution (once): 5 units
─────────
Total: 5 units / 10,000 limit (< 0.1%)

Example: 1 Channel, 8h Stream (REST Fallback Active)

Idle hours (16h): 16 * 60 = 960 units (broadcast poll)
Stream hours (8h): 8 * 1860 = 14,880 units (broadcast + chat poll)
─────────
Total: 15,840 units / 10,000 limit (158% -- OVER QUOTA)

REST fallback is disabled by default for this reason.

Quota Safeguards

MechanismDetails
InnerTube primary0 quota for all chat reception and broadcast discovery
DetectionHTTP 403 (REST) or RESOURCE_EXHAUSTED (gRPC)
Backoff5-minute pause on quota exhaustion (QUOTA_BACKOFF_SECS = 300)
Fallback chainInnerTube → gRPC → REST (each after 3 failures in 60 s)
REST togglerest_fallback_enabled = false disables REST fallback entirely
Shared cacheCopyright Worker and Bot read broadcast status from Redis, not YouTube API
Adaptive pollingREST fallback respects polling_interval_millis from YouTube's response

Requesting Higher Quota

To request a quota increase from Google:

  1. Pass the Quota and Compliance Audit
  2. Demonstrate compliance with YouTube API Terms of Service
  3. If previously audited within 12 months, use the Audited Developer Requests Form
  4. There is no published maximum — increases are granted case-by-case