> AI agents: this is one page from PostHog's docs. Full index of Markdown docs for LLMs: https://posthog.com/llms.txt

# Which accounts are ready to upsell? – Context Warehouse pocket guide

[](/pocket-guides.md)Aa

[](/pocket-guides/context-warehouse/onboarding-conversion.md)[](/pocket-guides/context-warehouse/pre-cancellation-behavior.md)

# Which accounts are ready to upsell? – Context Warehouse pocket guide

An account outgrowing its plan is ready for a chat with sales about expansion, if anyone notices in time. This Skill compares real product usage against each account's current Stripe plan limits and flags the ones consistently pushing past them.

## Example data and how to read it

The Skill looks for patterns like Fig. 1: Acme Co is running at 94% of its Growth plan's limit, month after month, a sustained pattern rather than a one-off spike. Globex is smaller in absolute terms but just as close to its own ceiling.

| Account | Plan | Usage (30d) | Plan limit | Utilization |
| --- | --- | --- | --- | --- |
| Acme Co | Growth | 94,200 | 100,000 | 94% |
| Northwind | Growth | 88,600 | 100,000 | 89% |
| Globex | Starter | 9,400 | 10,000 | 94% |

Fig. 1 – Example data: accounts pushing past their current plan's limits.

## Doing this by hand

1.  **Connect [Stripe](/docs/cdp/sources/stripe.md)** via [Data pipeline > Sources](/docs/data-warehouse/sources.md) for each account's current plan.
2.  **Write down your own plan limits**: Stripe rarely stores these, so you'll need your pricing page or internal docs.
3.  **Build a usage [Trends](/docs/product-analytics/trends/overview.md) insight**, broken down by account or group, for the metric your limits apply to.
4.  **Cross-reference** in a spreadsheet, open the [SQL editor](/docs/data-warehouse/sql.md), or ask PostHog AI to join usage against plan in one query and skip the spreadsheet.

## Get an agent to do the work

Copy the Skill below and add it to your agent. The agent works out each account's current plan from Stripe, the numeric limit that plan implies (often not in Stripe itself, so it asks), and the PostHog metric that maps to the limited resource. It flags accounts where usage ÷ limit clears a threshold while they're not already on the top tier, preferring a "consistently over" signal across a few months over a one-off spike. Because this is most useful fresh, it offers to materialize the query so it refreshes on a schedule.

This flags expansion by usage *against plan limits*. For account health measured as ARR versus engagement instead, that's [ARR vs engagement](/pocket-guides/context-warehouse/value-vs-engagement.md).

posthog-upsell-ready-accounts/SKILL.md

```markdown
# Which accounts are ready to upsell?
**Question:** Which accounts are consistently near or over their plan limits but still on a lower plan?
**For:** Sales & CS · **Difficulty:** Intermediate · **Shape:** a scheduled query
**Data sources:** PostHog events (usage vs plan limits & premium features) + Stripe (current plan per account)
## What this produces
A saved PostHog insight listing accounts whose measured product usage runs near or over the limits of their
current Stripe plan — a live, refreshable expansion list for Sales/CS.
## Workflow
First read `references/posthog-workflow.md` for the shared setup: confirm the PostHog MCP is connected, ensure the
Stripe source exists (secure connect-link flow if not), and learn the real schema. Then the question-specific part:
### 1. Identify the pieces in this project
- **Current plan per account.** From Stripe: the active `stripe_subscription` → `stripe_price` / `stripe_product`
  gives each customer's current plan. Confirm how the user names their tiers.
- **Plan limits.** The numeric limit each plan implies (seats, events, API calls, etc.). This often isn't in
  Stripe — ask the user for the limit per tier, or read it from a plan/product metadata field if they store one.
- **Real usage.** The PostHog metric that maps to the limited resource (e.g. count of a usage event per account per
  month, or distinct active users per group). Find it with `event-definitions-list` / `property-definitions`.
- **Account key.** Map usage to the Stripe customer (person email or a group's account id). See the join gotchas
  in the shared reference.
### 2. Build and validate the query
Adapt and validate with `query-run`. The core idea: usage ÷ plan limit ≥ threshold, AND plan is not already the
top tier.
```sql
-- Accounts whose usage is near/over their plan limit but still on a lower plan.
-- Adapt: usage event, the account key, plan→limit mapping (here inline as a CASE), and thresholds.
WITH usage AS (
    SELECT
        e.person.properties.account_id AS account,   -- or group key / email
        count() AS usage_last_30d
    FROM events AS e
    WHERE e.event = 'billable_action'                -- the resource you meter on
      AND e.timestamp >= now() - INTERVAL 30 DAY
    GROUP BY account
),
plan AS (
    SELECT
        lower(c.email) AS account,                   -- align this key with `usage.account`
        p.nickname AS plan_name,
        multiIf(p.nickname = 'Starter', 10000,
                p.nickname = 'Growth', 100000,
                p.nickname = 'Scale', 1000000, NULL) AS plan_limit,
        p.nickname != 'Scale' AS not_top_tier
    FROM stripe_subscription AS s
    INNER JOIN stripe_price AS p ON s.plan_id = p.id
    WHERE s.status = 'active'
)
SELECT
    pl.account,
    pl.plan_name,
    u.usage_last_30d,
    pl.plan_limit,
    round(u.usage_last_30d / nullif(pl.plan_limit, 0), 2) AS utilization
FROM usage AS u
INNER JOIN plan AS pl ON u.account = pl.account
WHERE pl.not_top_tier
  AND u.usage_last_30d >= 0.8 * pl.plan_limit          -- "near or over" threshold
ORDER BY utilization DESC
```
Prefer a "consistently over" signal (e.g. over threshold in 2+ of the last 3 months) to avoid flagging one-off
spikes — extend the usage CTE to bucket by month if the user wants that.
### 3. Save the insight and schedule it
Save as a SQL/HogQL table insight named "Upsell-ready accounts (usage vs plan)". Because this is most useful
fresh, offer to add it to a dashboard and to materialize the underlying query (`view-create` + `view-materialize`)
so it refreshes on a schedule.
## Self-driving development (offer this)
With a live list of accounts outgrowing their plan, the user can catch expansion moments as they happen. Offer to
help trigger an in-product upgrade prompt or a Sales/CS outreach alert for accounts that cross the threshold —
growing revenue without anyone watching a dashboard.
```

Show full example

Fig. 2 – The Skill itself, copy and paste this into your agent to answer the question.

See also: [ARR vs engagement](/pocket-guides/context-warehouse/value-vs-engagement.md) · [Revenue metrics](/pocket-guides/context-warehouse/revenue-metrics.md)

[‹ Which onboarding steps turn trials into paying customers?](/pocket-guides/context-warehouse/onboarding-conversion.md)[All guides](/pocket-guides.md)p. 3 of 15[What do customers do right before they cancel? ›](/pocket-guides/context-warehouse/pre-cancellation-behavior.md)