How to tell if an Apify user is paying

Apify exposes a single environment variable that tells your actor whether the user who triggered the current run is on a paid plan. This guide explains what APIFY_USER_IS_PAYING is, how to use it, and the gotchas worth knowing.

Use with an AI agent

Open this guide as a pre-filled prompt — or copy it for Claude Code, Cursor, Codex, or any other coding agent.

TL;DR

One line per language:

const isPaying = process.env.APIFY_USER_IS_PAYING === '1';

If the result is true, the user is on a paid Apify plan. If it's false, they're on the free tier — or this is local development.

What is APIFY_USER_IS_PAYING?

It's an environment variable that Apify injects into every actor run, based on the billing status of the user who started the run — not the actor's owner.

ValueMeaning
"1"The user is on a paid Apify plan.
"0" / unsetThe user is on the free tier — or you're running locally.

A few things to note immediately:

  • It's a string, not a boolean. Always compare with === "1" (JS) or == "1" (Python). A loose check like Boolean(process.env.APIFY_USER_IS_PAYING) will incorrectly return true for the string "0".
  • It's set per run, not per actor. The value reflects the billing status of whoever pressed Run(or called the API), not the actor's owner.
  • It's not set locally. During local development the variable simply isn't there. Wrap your check with Actor.isAtHome() if you want different local-vs-platform behavior.

A reusable tier helper

In most actors you want at least three buckets — paid users, free users, and yourself running locally. A small helper keeps the rest of your code clean:

import { Actor } from 'apify';

// Replace with your APIFY_USER_ID so you bypass your own gating.
const OWNER_ID = 'YOUR_APIFY_USER_ID';

/**
 * Returns one of: 'local' | 'owner' | 'paid' | 'free'
 *
 * 'local'  = running on your laptop, not on the Apify platform.
 * 'owner'  = the user who started the run is you.
 * 'paid'   = the user is on a paid Apify plan.
 * 'free'   = the user is on the free tier.
 */
export function getUserTier() {
  if (!Actor.isAtHome()) return 'local';
  if (process.env.APIFY_USER_ID === OWNER_ID) return 'owner';
  if (process.env.APIFY_USER_IS_PAYING === '1') return 'paid';
  return 'free';
}

Call it once at the top of main and switch on the result.

Common patterns

Gate premium output fields

The highest-leverage move: ship one actor, but make the dataset genuinely more valuable for paid users.

import { getUserTier } from './user-tier.js';

const tier = getUserTier();

const result = {
  url: page.url,
  title: page.title,
};

if (tier === 'paid' || tier === 'owner' || tier === 'local') {
  // Premium fields — slow or expensive to compute.
  result.fullText = page.fullText;
  result.summary = await summarize(page.fullText);
  result.entities = await extractEntities(page.fullText);
}

await Actor.pushData(result);

Watermark free-tier results

Add a _trial: true field (and an upgrade URL) to free-tier rows. It costs you nothing, makes the limitation visible in the dataset, and gives downstream tooling a way to filter or upsell.

if (tier === 'free') {
  result._trial = true;
  result._upgrade_url = 'https://apify.com/store/YOUR_ACTOR';
}

Cap usage for free users

If you want to cap results, throttle daily runs, or enforce a cooldown for free users, the companion guide Add free-tier limits to your Apify actor drops in a helper that bypasses anyone with APIFY_USER_IS_PAYING="1".

Bypassing for yourself

Apify also injects APIFY_USER_ID — the unique ID of the user who started the run. Most creators hardcode a bypass for their own account so they can test the actor as a regular user and never get gated out of their own thing. The tier helper above already does this — replace YOUR_APIFY_USER_ID with the value from console.apify.com → Account → Integrations.

Better still, lift it into an env var on your actor build so you don't leak it in source control.

Testing locally

Neither variable is set when you run the actor locally. To simulate the two cases:

# Simulate a paying user
APIFY_USER_IS_PAYING=1 apify run

# Simulate a free user
APIFY_USER_IS_PAYING=0 apify run

# If your code wraps the check with Actor.isAtHome(), also opt into platform mode:
APIFY_USER_IS_PAYING=1 APIFY_IS_AT_HOME=1 apify run

Caveats worth knowing

  • Don't trust this client-side. This is an actor-side flag, set by Apify on the run container. If you're serving a web app that calls your actor, do the gating server-side.
  • “Paid” is binary, not tiered. The flag doesn't tell you which Apify plan the user is on (Starter, Scale, Business…). If you need plan-level gating, look the user up via the Apify API with APIFY_TOKEN.
  • Trials count as paid. Users on an Apify trial show up as paying. That's almost always what you want — they're evaluating your actor with real intent.
  • The value can change between runs. A user can churn, then come back. Don't cache it in long-lived storage as if it were immutable.
  • Owner ID ≠ paying. You can be the actor's creator and still get APIFY_USER_IS_PAYING unset if your own account is on the free tier. Check both flags if you need an owner bypass.

Related env vars

Apify injects a handful of useful env vars on every run. The ones worth knowing alongside APIFY_USER_IS_PAYING:

VariablePurpose
APIFY_USER_IDID of the user running this run. Use it for an owner bypass.
APIFY_USER_IS_PAYING“1” if they're on a paid plan, else unset.
APIFY_IS_AT_HOME“1” when running on the Apify platform. Actor.isAtHome() wraps this.
APIFY_ACTOR_IDYour actor's ID — handy for cross-actor logging.
APIFY_ACTOR_RUN_IDThis run's ID — handy for linking back from external systems.
APIFY_TOKENAPI token for the run. Don't log it.

Where to go next

Spotted a bug, or want a guide on something else?

support@mail.apifyhub.com