Skip to content

Rate Limits Explained

sarangshahane edited this page Aug 25, 2026 · 1 revision

Rate Limits Explained

Every question costs you an API call, so the plugin limits how fast anyone can ask for them. Two limits apply to question generation, and one to answer submissions.

The defaults

Limit Value Scope
Per visitor 5 per minute Generation, keyed on IP address + browser User-Agent
Per IP 15 per minute Generation, keyed on IP address alone
Answers 5 per minute Answer submissions, per visitor

Generation is charged against both generation limits. A visitor hits whichever runs out first.

The window is a fixed 60 seconds that resets on the minute boundary, not a rolling window. A practical consequence: five requests at 0:59 and five more at 1:01 are both allowed, so the real short-term burst ceiling is double the number in the table.

Why there are two generation limits

The per-visitor bucket includes the browser's User-Agent, which the caller controls. On its own, that means anyone could change one header and get a fresh allowance — an unbounded API bill from a single machine.

The per-IP ceiling closes that. It is keyed on the address alone, so rotating headers gets you nowhere. The finer per-visitor bucket is kept as well, so genuine visitors sharing one office IP are not lumped together at five per minute between them.

What a visitor sees

Please wait before requesting another question.

They do not see which limit they hit, or how long is left. The wait is at most 60 seconds.

Changing the limits

The ai_fq_rate_limit filter receives the current limit and the bucket it applies to, so you can adjust each independently:

add_filter( 'ai_fq_rate_limit', function ( $limit, $bucket ) {
    if ( str_starts_with( $bucket, 'generate-ip|' ) ) {
        return 40;   // per-IP ceiling
    }
    if ( str_starts_with( $bucket, 'generate|' ) ) {
        return 10;   // per-visitor generation
    }
    if ( str_starts_with( $bucket, 'answer|' ) ) {
        return 10;   // answer submissions
    }
    return $limit;
}, 10, 2 );

Bucket prefixes are generate|, generate-ip| and answer|.

Zero and negative values are ignored. Returning 0 does not disable rate limiting — the plugin falls back to the default for that bucket. This is deliberate: the rate limiter is the only thing standing between a public endpoint and your provider bill, and a filter typo should not remove it.

There is no upper bound, so a large number effectively disables the limit. That is your decision to make, but understand what you are switching off.

Multiple widgets on one page

Each widget fetches its own question when the page loads, and each fetch counts. A page with six widgets uses six of the per-visitor allowance immediately, so the sixth shows the wait message.

If you want a page of several widgets, raise the per-visitor generation limit to at least the number of widgets plus a little headroom for the visitor pressing "Next Question".

Behind a proxy or CDN

If your site sits behind Cloudflare or any reverse proxy, the address the plugin sees is the proxy's, not the visitor's. Every visitor then shares one per-IP ceiling, and 15 requests a minute across your whole audience is not enough.

This needs fixing or the widget will appear broken at scale. See Running Behind Cloudflare or a CDN.

The rate-limit table

Counters live in one table created on activation: a hashed bucket key, a window timestamp, and a count. No question text, no answers, nothing identifying.

An hourly scheduled task deletes rows older than a day, and each request clears its own stale windows, so the table does not grow.

If that table is missing, the limiter fails closed — every request is refused and every visitor sees the wait message permanently, even on an idle site. Deactivating and reactivating the plugin recreates it.

Clone this wiki locally