> ## Documentation Index
> Fetch the complete documentation index at: https://docs.crxbase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# FAQ & troubleshooting

> Answers to common questions and solutions for known issues.

## Frequently asked questions

<AccordionGroup>
  <Accordion title="Which browsers are supported?">
    crxbase works with any Chromium-based browser (Chrome, Edge, Brave, Arc, etc.) and Firefox.
  </Accordion>

  <Accordion title="Does it work with extension frameworks like WXT or Plasmo?">
    Yes. The `@crxbase/payments` library works in any environment — WXT, Plasmo, vanilla Manifest V3, or any other framework. Import and use it in your
    background script, content script, or popup.
  </Accordion>

  <Accordion title="What is the platform fee?">
    crxbase charges a **5% fee** on each transaction. This is deducted automatically by Stripe during payment processing.
  </Accordion>

  <Accordion title="Can users have multiple plans?">
    Users can have **one active recurring subscription** (monthly or yearly) across all tiers, plus **one lifetime purchase per tier**. A lifetime purchase at a
    given tier blocks new subscriptions in the same tier or a lower tier. See [plan switching](/guides/platform/plan-switching/) for the full interaction rules.
  </Accordion>

  <Accordion title="How long do user sessions last?">
    Sessions last **90 days**. After that, `getUser()` returns `null` and the user needs to log in again. See [authentication](/guides/platform/authentication/)
    for details.
  </Accordion>

  <Accordion title="What happens when a subscription payment fails?">
    The plan status changes to `past_due` and Stripe retries the payment automatically. During the current billing period, `getUser()` can still return `paid: true`.

    After Stripe finishes retrying, the final subscription status depends on your [automatic collection settings](https://dashboard.stripe.com/settings/billing/automatic). crxbase recommends setting Stripe to cancel the subscription after retries fail. Users can update their payment method through the Stripe portal (`client.openManagePage()`).
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="getUser() returns null for a logged-in user">
    The user's session has likely expired (90 days) or they were signed out. Call `client.openLoginPage()` to prompt the user to log in again.
  </Accordion>

  <Accordion title="OTP code not working">
    OTP codes expire after **10 minutes**. There is also a rate limit of **5 OTP requests per 10 minutes** per email. If the code has expired, the user should
    request a new one.
  </Accordion>

  <Accordion title="RATE_LIMITED error">
    The API allows a maximum of **2 requests per second**. Add delays between requests or reduce polling frequency. Handle the error:

    ```typescript theme={null}
    try {
      const user = await client.getUser();
    } catch (error: any) {
        if (error?.name === "rate_limited") {
        // Wait and retry after a delay
      }
    }
    ```

    Match the exact string from [Error handling](/guides/library/error-handling/) when checking `error.name`.
  </Accordion>

  <Accordion title="Plan status shows past_due or unpaid">
    * `past_due` - a renewal payment failed. The user can keep paid access until the current billing period ends.
    * `unpaid` - Stripe marked the subscription unpaid after payment recovery failed.

    Direct the user to update their payment method:

    ```javascript theme={null}
    client.openManagePage();
    ```
  </Accordion>
</AccordionGroup>

## Need help?

Contact us at <a href="mailto:support@crxbase.com">[support@crxbase.com](mailto:support@crxbase.com)</a>.
