# Access and features

> Who may use a tool, what they get before paying, and which features each plan unlocks.

Two questions, in the **Access** card at the top of the tool's **Pricing** page: whether using it needs an **account** at all — the *Require an account* switch — and what a person gets **before paying**: *Everything free*, *Free uses* or *Nothing free*. Everything a tool can be is the two composed, so there is no list of shapes to pick from. The card writes back the sentence your buyers meet — &#x2A;Anyone can use Tab Tidy. It is free for 5 uses per device, then a plan.*

Installed copies see a change within seconds on Test. On Live, a copy asks Toolaby at most once in five minutes when the Toolaby popup opens, and every hour otherwise: a change shows within an hour, and within 6 minutes where the Toolaby popup opens. The card says so once saved.

**Preview**, at the top of the **Pricing** page, opens the popup beside the page: the panel a buyer meets in each of its states, in your brand, as saved.

## An account

| Require an account | The extension                                                                                                                                                                                                                                                                                                                                                                  |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Off                | Anyone can use it. Signing in brings what they bought, on any device.                                                                                                                                                                                                                                                                                                          |
| On                 | Nothing works until they sign in: `gate()` refuses with `sign_in`, the Toolaby popup asks for an account and your own popup is not opened. A licence key is a purchase, not an account, so it does not stand in for one — the device is asked to sign in with the address that bought, and the purchase is waiting there. Signing out from the account bar returns them to it. |

With nothing free, the two account choices look the same to a stranger — the plans, either way, because the price should not be a screen away and buying asks for an account anyway. They differ afterwards: a pasted licence key unlocks on its own where an account is optional, and is asked to sign in where it is required; and signing out returns to the sign-in panel there.

## Before paying

| Choice          | `access`    | The extension                                                                                                                                                                                    |
| --------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Everything free | `open`      | Nothing is counted; only the version is checked. A feature a plan sells is still refused until bought: `open` is the tool's use.                                                                 |
| Free uses       | `free_uses` | Works until the uses you set are spent, counted on Toolaby **per device**, or **per account** where the tool requires one: in total, or each day, week or month. Then the paywall offers a plan. |
| Nothing free    | `paid`      | A paid extension: shows the paywall until the person holds a plan, a trial or a grant. There is no Free plan: it is not a card on your Pricing page and not a column on your checkout page.      |

The six combinations, and what each is for:

| Require an account | Before paying   | What it is                                                                                                                                                                                                                                      |
| ------------------ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Off                | Everything free | A free tool; paid plans add features.                                                                                                                                                                                                           |
| Off                | Free uses       | The classic freemium extension: try it, then pay.                                                                                                                                                                                               |
| Off                | Nothing free    | Paid up front; a licence can be bought without an account and claimed later.                                                                                                                                                                    |
| On                 | Everything free | Free, but you know your users.                                                                                                                                                                                                                  |
| On                 | Free uses       | An account first, then a trial run of the tool.                                                                                                                                                                                                 |
| On                 | Nothing free    | Sign in and subscribe, as a web app. The popup shows the plans first — the price should not be a screen away — with *Already bought it? Sign in* under them. Someone who bought and has not signed in is shown the way in, not the price again. |

Both are enforced in two places with one rule:

* The **Toolaby popup**, at every open: it opens your popup when the device may use the extension, and shows the sign-in or the plans when it may not. Where your code counts uses with `gate()`, opening spends none; see [The Toolaby popup](https://toolaby.app/docs/toolaby-popup.md#when-it-opens-your-popup).
* `gate()`, wherever you call it: it answers `{ allowed: false, reason }` with `reason` one of `sign_in`, `paid`, `limit` or `feature`. It also answers `count` for a `count` that is not a whole number from 1 to 1000, and `refused` when Toolaby refused the request: see [Permit](https://toolaby.app/docs/reference/objects.md#permit).

The account and `open` are decided on the device from the policy Toolaby signed. Only metered uses (`free_uses`) make a request, to count the use.

## Who the uses are counted for

| Require an account | Counted for                                         | A new device                                                                                                          |
| ------------------ | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Off                | The device                                          | Starts a count of its own. Removing the extension and adding it again, or clearing its site data, makes a new device. |
| On                 | The account's inbox, on every device it signs in on | Spends the account's count.                                                                                           |

An account's count is its inbox's, as a trial is: the address without a `+tag`, and for Gmail without dots. `maya+2@example.com` and `maya@example.com` spend one count, and so does an account deleted and made again with the same address. Toolaby keeps the inbox as a keyed hash, never the address, and keeps it after the account is deleted.

An address from a throwaway mail service, such as mailinator.com, or one that is not verified, has no count of its own, just as it has no trial. All such accounts of the tool spend one count together, so a new throwaway address never brings the uses back. That count starts again with the tool's period: each day, week or month, and each day at midnight UTC where the uses are counted in total, so no one can spend it for good.

`gate()` says so with `sharedUses: true`, and the Toolaby popup tells the person to sign in with their own address. A device still keeps its own count for each account, as below: where the uses are counted in total, an account that spent them on a device stays refused on that device the next day too, and each of its tries there still takes one of the day's shared uses. Forwarding services such as DuckDuckGo's or Apple's Hide My Email are inboxes of their own.

Two accounts on one device each have their own uses. The device's meter, which decides offline, follows the account signed in, and keeps the counts of the last eight accounts that used the tool there.

A device is the key pair the extension makes at its first run ([How it works](https://toolaby.app/docs/how-it-works.md)). When one address registers an unusual number of new devices in a day, Toolaby records *Many installs from one IP*, naming the first new device. The event shows on the Customers timeline of the buyer who signs in on that device, or activates a licence there. It refuses nothing. To keep a reinstall from giving the uses again, require an account.

## Free uses a day, a week or a month

Beside the number of free uses, the **Access** card asks how often they start again: *in total*, *a day*, *a week* or *a month*. Toolaby counts them in UTC, on its own clock: a day from midnight, a week from Monday, a month from the 1st. A daily allowance is a setting, not code: a count kept by the extension starts again whenever its storage is cleared, which Toolaby's does not.

* `gate()` answers the period and when more come: `{ allowed: false, reason: 'limit', per: 'day', resetsAt }`, with `resetsAt` a `Date` (not in an answer given offline). `getUser().usage` has `per` and `resetsAt` too.
* Changing the period never gives a device new uses in the window it is in: one that used the tool today keeps today's count until the next window. Moving to *in total* carries each device's count in the current window on as its count in total.
* The Toolaby popup's meter says *2 free uses left today*, and when more come, in the buyer's own time: *More at 03:00*.
* A day holds at most 200: a device asks for free uses at most 200 times a day.
* An offline device does not start a new day by its own clock. It waits for Toolaby to name the new window.
* A copy whose `toolaby.js` is older keeps counting them in total until you run `npx -y toolaby@latest upgrade` and publish the build. `check` says when it is older (`CLIENT_OUTDATED`).

From the command line or a coding agent: `npx -y toolaby@latest access <tool-id> --access free_uses --free-uses 3 --free-uses-per day`.

## Signing out

The account bar's **Sign out** (and `signOut()`) clears the device's credential and revokes its link on the account, so the account page's Devices stop listing it. What the person is left with follows the account switch: **optional**, they drop to the Free plan and keep using the tool — the meter resumes where it was, since signing out is not a way to refill it; **required**, the tool stops and the popup returns to Toolaby's, asking for an account. Someone who holds a paid plan is asked to confirm first.

## Features

Without features, a paid plan unlocks the whole tool: `user.paid` is the only question.

Under the tool's **Pricing**, the **Features** card lists what the tool can do — *Export*, *Sync* — and which tiers hold each one, and whether the Free plan does. The card takes entries once the tool has a paid plan.

Each feature has a name, which buyers read on the paywall and the checkout page, and a key, which your code asks for. A plan's card lists the names of the features it holds, the free ones too, and nothing else. **Add feature** opens a form with **Name** and **Key**, and makes the key from the name — *Export* becomes `export` — unless you type one: name it *Export to Excel*, key `export`.

A name or key another feature already has is refused, with the feature that has it named under the field; so is a name no key can be made from, until you type one. A new feature joins the grid marked *New*, and **Save** keeps it with the plans you tick. The grid shows each key under its name.

```js
if (await toolaby.has('export')) showExportButton();          // no request

const permit = await toolaby.gate({ feature: 'export' });      // one use of the feature
if (!permit.allowed) return permit; // reason 'feature', feature 'export', needs ['team']
```

* `has(feature)` answers from the device: true for a Free plan feature, or when the last token lists it. A tool with no features holds everything.
* `gate({ feature })` refuses with `reason: 'feature'` and `needs`, the ids of the plans that hold it. The paywall then offers only those plans.
* `getUser().features` lists the keys the device holds; `null` means everything.

Tokens issued before a tool had features, and grants with no features named, unlock everything.

### Archiving a feature

A feature's key belongs to it for good. Your code asks for it, so it never changes and never comes back as another feature. The **Archive** button beside a feature takes it off sale without breaking anything:

|                                                | An archived feature                                                                                     |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| The checkout page and the plan lines           | No longer list it                                                                                       |
| Plans that held it                             | Still hold it, and so do the people on them                                                             |
| A free feature                                 | Stays free                                                                                              |
| `has('export')`, `gate({ feature: 'export' })` | Answer as before, in every copy already installed                                                       |
| Its key                                        | Kept: typing the same key under **Add feature** offers **Restore**, which lists it again under its name |

Archived features are listed under the grid, each with **Restore**. To take a feature away from people, untick it on their plans first; archiving never takes anything. `npx -y toolaby@latest check` warns `FEATURE_ARCHIVED` where code still gates on one, so you can take the check out in your next release.

The command line and the MCP server work the same way: `toolaby_set_features` takes the whole list to show, and a feature the list leaves out is archived, not deleted.

## Writing the checks early

A `has()` or `gate({ feature })` written while the Free plan holds everything answers yes. When you later move the feature to a paid plan, the same line starts gating. The Toolaby popup asks for the policy when it opens, on Live when the last answer is five minutes old; an extension that only calls `gate()` learns of a change within the hour.

## A free allowance of items

A limit that is not a number of uses — two saved sessions, five projects — is yours to count, since only your code knows what is stored. Keep **Before paying** on *Everything free*, sell a feature such as `unlimited-sessions`, and ask for it only past the allowance:

```js title="background.js"
async saveSession(tabs) {
  const saved = await sessions.count();
  if (saved >= 2) {
    const permit = await toolaby.gate({ feature: 'unlimited-sessions' });
    if (!permit.allowed) return permit; // the page calls toolaby.showPaywall(permit)
  }
  return sessions.save(tabs);
}
```

Deleting an item makes room again, which a meter of uses never does. Toolaby does not know the allowance, so say it where buyers read: name the feature for what it lifts — *Unlimited sessions*, which the paywall shows as *Unlimited sessions is in Pro* — and put the number in the tool's one line under **Settings**, shown on the checkout page under its name.

## Moving from a meter to features

A bare `gate()` asks for a use of the tool. After you release a version that gates by feature instead, every copy of the older version still installed keeps asking for uses — and *Everything free* holds the tool's use, so switching to it lets those copies through without counting. Change the dashboard in this order:

1. Add the features and tick them on the plans that sell them. Leave **Before paying** on *Free uses*: the older version is counted as before, and the new one refuses a paid feature to anyone who has not bought it, exactly as it will under *Everything free*.
2. Publish the new version.
3. Once it has reached your users, set **Before paying** to *Everything free*. Chrome checks for extension updates every few hours, but only while it is running, so allow a few days after the store publishes.

Until then, the new version's bare `gate()` calls, and any feature the Free plan holds, still spend uses.

The command line and the MCP server keep this order for you, and so for a coding agent: while copies have checked in this week, `npx -y toolaby@latest access <tool-id> --access open` is refused with the versions installed, until you add `--now`. Copy to Live leaves Live on *Free uses* the same way, and says so.
