Rate limiting by IP, user or key: choosing a subject
A limit has to count something against somebody, and choosing that somebody is a design decision rather than a detail. The subject you pick decides who gets inconvenienced when the limit fires, and every available choice is wrong for somebody, in a way that is better known in advance.
The three candidates
Each identifies a different thing, and none of them identifies a person.
The network address is available for every request, including the first one, and requires nothing from the client. That makes it the only subject that works before anybody has identified themselves, which is why it is the default nearly everywhere.
The account is available once somebody has signed in, and it identifies the party you care about. A limit counted against an account survives the visitor changing networks, which an address-based limit does not.
The key is available for programmatic clients and identifies an integration rather than a person. It is the most precise of the three, and it exists only where you issued something to count against.
The pattern is visible immediately: precision and availability run in opposite directions. The subject you always have tells you the least, and the subject that tells you the most is not there when you need it most.
Why the address is wrong more often than expected
The failure here is not occasional.
Shared networks put many people behind one address. An office, a university, a mobile carrier, a country-scale provider: all of them can present hundreds or thousands of unrelated visitors as one. A limit that would be generous for a person is restrictive for a building, and the people affected have no idea why, because nothing they did caused it.
One person can present many addresses. Mobile clients change networks mid-session, and connections through pools of addresses can vary between requests. A limit counted against an address is then counting against something that keeps changing identity while the behaviour stays the same.
Addresses are shared over time as well as at a moment. An address assigned to somebody abusive in the morning may belong to an ordinary visitor in the afternoon, so a decision that outlives its cause punishes whoever inherits it. This is the same property that makes reputation lists lag reality, covered under IP reputation.
There is also a cost you do not see. The visitors turned away by a limit aimed at somebody else rarely report it; they conclude the site is broken or slow and go elsewhere, so the damage arrives as absence rather than as a complaint you can investigate.
None of that makes the address useless. It makes it a coarse subject that should be used with limits set for a crowd rather than for a person, and with the knowledge that it will occasionally be wrong about who it is counting.
Choosing by what you are protecting
The subject follows from the thing at risk, not from preference.
Protecting a public endpoint from volume. The address is what you have, so it is what you use, with a threshold that assumes the address may be a crowd rather than an individual.
Protecting an account from abuse. Count against the account. Somebody attacking one account from many addresses is invisible to an address-based limit and obvious to an account-based one.
Protecting an expensive operation from a legitimate integration. Count against the key. The integration is not hostile; it is enthusiastic, and a limit here is a contract rather than a defence.
Protecting a scarce resource shared by everybody. Where the thing being protected is capacity rather than a specific account, the honest subject is the total, and per-subject limits are a blunt proxy for it.
Protecting sign-in itself. This is the case where the subject is least obvious, because there is no account yet in the sense that matters: the whole point of the attempt is to establish one. Counting against the address catches broad attempts and misses distributed ones; counting against the account name being tried catches the distributed ones and can be used to lock out a real owner deliberately. Doing both, with different thresholds, is the usual answer.
What the platform provides here
Stated separately from the design advice above, and narrowly.
Rate limiting is applied per domain, which is the unit the limits are counted against. That is a coarser subject than anything on this page and should be understood as such: it bounds what a domain accepts in total rather than what any single visitor, account, or integration may do.
Everything else above is guidance for designing limits, whatever enforces them. Where a finer subject is needed, it belongs wherever your application knows about accounts and keys, because that is where the identity exists.
Before enforcing any of this
One habit prevents most of the damage.
Whatever subject you choose, watch what the limit would have done before it does it. The counting is the easy part; discovering that your chosen subject groups your largest customer into one bucket is the part that hurts, and it is visible in advance, as covered under monitor mode and operations.
Questions
Should I rate limit by IP or by user?
By whatever identifies the thing you are actually protecting. Addresses are always available and identify a network rather than a person; accounts identify the party you care about, but only after somebody has signed in. Most systems end up needing both, applied to different situations rather than layered on the same one.
Why is IP-based limiting unfair on shared networks?
Because an office, a campus, or a mobile carrier can present many unrelated people as a single address. A threshold that is sensible for one individual becomes restrictive for an entire building, and none of the people affected can tell why, since their own behaviour was completely ordinary.
Can attackers get around IP limits?
Distributed attacks make address-based limits much less effective, because each individual source stays comfortably under any per-address threshold. That is an argument for choosing subjects deliberately and for watching totals as well as individuals, rather than an argument against limits, which still stop the simpler cases outright.
What about limiting by session?
A session identifies a browser rather than a person or an account, and it can usually be discarded and replaced without effort by anybody who wants to. It is useful for shaping ordinary use, and it should never be the only subject protecting anything that actually matters.
Rate limiting is applied per domain — a coarser subject than anything on this page, and stated as such.
off
Nothing is counted against anything.
monitor
What the chosen subject would have grouped together is visible before it refuses anybody.
block
The limit is enforced against the domain, and refusals are still recorded.