RFC 0014 - EventSub Subscription Limit Changes

Summary

EventSub enforces a limit on the maximum number of subscriptions a developer’s application can create, which today defaults to 10,000. Twitch is changing this logic so the maximum number of subscriptions automatically grows with your application’s user base.

Motivation

Developers’ applications have a default subscription limit of 10,000. When a developer needs an increased subscription limit, they first need to make a request to Twitch and justify the increase. These requests require a review and can take a considerable amount of time to process.

Even after a subscription limit is increased, the limit is still a static value. If a developer’s application continues to grow or if they wish to take advantage of more subscription types, they will need to create more subscriptions and thus may need to request another limit increase. This adds friction to application growth and development.

We want to reduce friction on developers by automatically increasing the number of subscriptions their applications can create as their user base grows.

Proposed Solution

If a user has authorized your application, your application can create unlimited EventSub subscriptions for that user.

Note that this proposal ONLY changes how EventSub determines whether you’ve created too many subscriptions or not. Everything else is staying the same:

  1. This proposal does not change authorization requirements for subscriptions. If a subscription type requires an OAuth scope, the application still must possess that scope to create the subscription.

  2. EventSub will still forbid creating the same subscription more than three times. A subscription is considered a duplicate if there exists another subscription with the same type, version, and condition.

Example

Suppose a developer wants to create three subscriptions for every user:

  1. “channel.update” (doesn’t require any OAuth scopes)
  2. “channel.follow” (doesn’t require any OAuth scopes)
  3. “channel.cheer” (requires the bits:read OAuth scope)

User A has granted authorization to the developer’s application and that authorization includes the bits:read OAuth scope. Then the developer could create all three of those subscriptions without impacting their limit.

User B has granted authorization to the developer’s application, but the authorization only includes the channel:moderate OAuth scope. The developer could create subscriptions #1 and #2 without impacting their limit, however could NOT create subscription #3 (they’re missing the required OAuth scope).

User C has NOT granted authorization to the developer’s application. The developer could create subscriptions #1 and #2, but it WOULD impact their limit. They could NOT create subscription #3 (they’re missing the required OAuth scope).

This is summarized in the following table:

channel.update channel.follow channel.cheer
Authorized with bits:read scope No Impact on Limit No Impact on Limit No Impact on Limit
Authorized without bits:read scope No Impact on Limit No Impact on Limit Unauthorized
Not authorized Impacts on Limit Impacts on Limit Unauthorized

Detailed Changes

We will update subscription payloads to clarify which subscriptions impact your limit. To do this, we will add the following vocabulary:

  • Cost: How much the subscription counts against your limit. Subscriptions cost 0 if the user has authorized your application; otherwise they cost 1.

  • Total Cost: The total cost of all of your subscriptions for your application.

  • Max Total Cost: The maximum value of Total Cost allowed for your application.

Let’s consider an example where a developer’s application has been granted authorization for user 123, but not for user 456. Thus subscriptions for user 123 will have “cost: 0” but subscriptions for user 456 will have “cost: 1.”

Here’s what the “List Subscriptions” API response would look like:

{
	"data": [{
        	"id": "26b1c993-bfcf-44d9-b876-379dacafe75a",
        	"status": "enabled",
        	"type": "stream.online",
        	"version": "1",
        	"condition": {
           	 	"broadcaster_user_id": "123"
        	},
        	"created_at": "2020-11-10T20:08:33Z",
        	"transport": {
            		"method": "webhook",
            		"callback": "https://this-is-a-callback.com"
        	},
		"cost": 0
    	},
    	{
        	"id": "35016908-41ff-33ce-7879-61b8dfc2ee16",
        	"status": "enabled",
        	"type": "stream.online",
        	"version": "1",
        	"condition": {
            		"broadcaster_user_id": "456"
        	},
        	"created_at": "2020-11-10T20:31:52Z",
        	"transport": {
            		"method": "webhook",
            		"callback": "https://this-is-a-callback.com"
        	},
		"cost": 1
    	}],
	"total": 2,
	"total_cost": 1,
	"max_total_cost": 10000,
	"pagination": {}
}

A subscription’s “cost” will automatically update if the user grants or revokes authorization from your application. If an update to a subscription’s '“cost” causes the value of “total_cost” to exceed “max_total_cost,” the offending subscription may be revoked.

Transition Plan

EventSub will match your application’s “max_total_cost” to whatever your subscription limit is currently, which defaults to 10,000.

The “cost” field will be added to all subscriptions. EventSub will start respecting “total_cost” and “max_total_cost” when enforcing subscription limits.

We will deprecate any “limit” fields on EventSub payloads since they’re no longer used, and remove them after 3 months.

Once this transition is complete, developers will immediately be able to create more subscriptions than before, without requesting a subscription limit increase from Twitch.

11 Likes

SHIP

IT

Words to bypass spam filter

4 Likes

This seems like an amazing change. I know I for one would absolutely love for this to be implemented, and it would make it really easy as my application grows as to not have to put in a limit increase request.

My only other interest that I’d like to see added is a way to automatically delete subscriptions once a revocation has been made.

A subscription’s “cost” will automatically update if the user grants or revokes authorization from your application.

If an update to a subscription’s '“cost” causes the value of “total_cost” to exceed “max_total_cost,” the offending subscription may be revoked.

I for one don’t subscribe to any Events for users that haven’t authorized my application, especially now that CLI exists for testing events. I know previously some developers would subscribe an event to larger streamers either for testing of events, or for stress testing their notification systems.

With this change I could listen to the Revoke event, and then manually delete events that now have a cost to them. But this is additional resource use, such as bandwidth, API request-per-second limitations, etc.

It’d just be nice to delete any events related to a user as soon they revoke, rather than the cost ever increasing.

Otherwise, I’m with Barry. Best change.

4 Likes

This would be a highly welcome change, thank you!

To clarify, does above suggest that subscriptions with cost 0 will be treated as cost 1 during the transition period?

Great change! Very Welcome, Such WOW!image

1 Like

Great question @prod!

During the transition the cost field will be set to its correct value:

  • 0 if you have auth
  • 1 if you don’t have auth

EventSub’s limiting logic checks that num_subscriptions <= max_subscriptions. After we have updated all subscriptions to have a cost, we’ll change that limiting logic to be total_cost <= max_total_cost.

1 Like

This would be much appreciated. The only thing has been holding back an integration previously is the rate limit.

The one concern I can see here, @Jordan_Potter is an application like my Now Live bot, which never requires privileged scopes from any user and as such never requests users to authorize on their accounts. The app just uses an app access token to get public data. My users track potentially dozens of their favorite streamers to receive notice when the go live. Is there anything on the roadmap to handle situations like these dynamically or will those like me still be bound by having to request higher limits as the app grows?

For your use case where you’re trying to subscribe to topics for a broadcaster that doesn’t even use your app would be that you have to stay within the 10k limit, poll the API, or work with the broadcasters you’re tracking data of.

1 Like

Webhooks were initially brought out to eliminate a lot of the polling that needs to be done on the API. And since EventSub is the latest incarnation of the webhook system, it is left to believe that much of the same mentality applies.

And working with over 1,350 individual broadcasters (approximate number being tracked as of this posting) just feels like an absolute terrible workaround for data that is not utilized by my service.

All in all, this change just feels like it was developed without taking into consideration larger scale project use-cases that don’t require scoped data and it will make it difficult in the future to continue to scale as needed. Granted, I already have an elevated quota for EventSub, but I now worry about what will happen when I get closer to hitting that hard cap. Will I have to introduce fluff features that are likely to not be used by a large enough customer-base to justify the development time just to save on a few dozen subscriptions in my limit? Will I have to beg and plead for a limit increase like I already have to do with YouTube?

Just curious, how did you “pick” those 1350 broadcasters? If you are tracking them, either they opted in to your service, or someone would have to have gone in to hand select them no? usually “tracking” services are either opt in, or sites like analytics track literally everyone. if someone hand picked them, can the criteria be modified to stay within the limits? if the broadcaster themselves isn’t opting in, then there may not be a need to hit that hard limit IMO. Not trying to nit pic your business practices, just curious.

My product is a Discord bot that announces when streams go live. Users invite the bot (currently in ~3,200 servers) and select the broadcasters they wish to have announced in their Discord server(s). I get users from individual streamers wanting their personal streams, or their favorite streams, or community member streams announced all the way up to to e-sports organizations who want their team members announced in their official Discord servers. [And many use-cases in between] I personally don’t choose a single broadcaster to be tracked outside of my own personal Discord server.

So they are opting in themselves. so part of the onboarding, just quickly have them go through oauth once, then you get the benefit of this RFC.

I think you’re missing the point here. Not everyone that uses the bot uses it for their own stream. Sure, maybe about 10% use it only for their own streams, but the remaining 90% use it for other people’s streams. Do you think Ninja or Soda need a bot like mine to notify ppl when they are live? Nope, but I have at least a dozen servers tracking when either of those 2 go live so they get the notifications in the format they choose in their Discord servers. So any sort of onboarding prerequisite will GREATLY limit the broadcasters that can be tracked and announced because it would be an all or none process.

Imagine getting a bot that does what mine does and when trying to add a channel to get announcements for a particular channel, it would respond with "Sorry, but that channel hasn’t finished the onboarding process so I can’t announce them here. :man_shrugging: ". Nobody would want to use that product.

Oh, I see what you mean. Like I said, I wasn’t trying to nit pick, just trying to figure out the use case. That does make sense to me.

So that makes me think, maybe one of the fields when registering an eventsub for public data could be like “on behalf of” so if you have Discord owner JSMITH, and they want subscriptions, they get up to 10K on your app, so they can listen for 10K streamers, but you would use 1 App token still to sign up.

Without monetisation of this product, even when you scale up to many streamers, eventually you’ll start burning money.

So, this product/use case lends itself to to being “self hosted” and thus the user wanting it would provide their own ClientID/Secret, which then negates the problem of the rate limit. Since people would run their own instance with their own keys.

You’ll only get so far on your “master key set”. And/or spare server capacity/free cloud usage tiers.

Eventually you are either losing money or your hit the limit of subscriptions. So the ultimate fix, is people provide their own keys either to a self hosted copy, or to you, but of course, people shouldn’t be distributing their client secret…

So, even if you have infinite topics, you still have the “server cost” problem eventually. Or even, the Discord Rate limit problem. Depending on how much you are sending where.

It is monetized with a free basic tier, so there is no financial concerns.

And the way Discord rate limits work is the buckets are guild/channel specific, so each channel in each server has its own rate limit. I’ve had this project running for about 4 years, so all that has been worked out at this point.

Until your “free tier users” out pace the paid tier users. it just moves the problem (if you have infinite topics).

anywho we are wandering way off topic here since we are debating your specific product instead of the RFC itself

@Ague yep, I agree with you. This RFC does not help your use case much, since the majority of the events you’re listening for aren’t for users of your application.

I just want to highlight one of the (probably obvious) reasons why we have limits: Most third-party developers are good actors and we want to continue helping them grow. However naturally there are some bad actors too. And sometimes it’s difficult to tell whether they’re a good actor or bad actor without scrutiny. And sometimes good actors later become bad actors. We review applications, but in reality we should create a system that deters bad actors in the first place.

I don’t want this conversation to turn into “but what is good and what is bad” (someone is going to quote the infamous line from Hamlet). I just want to paint a picture that there are conflicting interests at play. And in the past we solved this by enforcing static thresholds on every developer that constantly had to be reviewed and adjusted by a human.

When designing this RFC, the goal was to create a strategy that we were confident would benefit the vast majority of good actors while not encouraging bad actors. It was tremendously hard to strike the right balance, and we considered dozens of approaches.

We settled on the above RFC, realizing that it would benefit the majority of good actors, but not all of them. Please don’t think we were neglecting your use case – we were just trying to strike a difficult balance. This is why we made the max_total_cost field adjustable. For good actors that don’t benefit from this RFC, we adjust max_total_cost (as you mentioned, you already benefit from this).

Lastly, I just want to mention that the proposed strategy isn’t taking away your ability to scale. We’re not suddenly reducing the number of subscriptions developers can create. We’re merely auto-scaling subscriptions where we’re confident it’s safe to do so.

3 Likes

The EventSub team has implemented the new cost-based subscription limits and the EventSub documentation has been updated accordingly as of today.