Skip to content

Getting started


We will rely on what's known as Password Based Encryption concept. You (or your users) provide a "secret", which will then be used to generate and manage API tokens as well as cover all data hashing and encryption needs. The JavaScript client hashes the "secret" (i.e. login credentials) in the browser, so the secret itself is never sent to the server.

Include PrefsDB

First, include the prefsdb client in your page. It defines a global PrefsDB class.

<script src="https://prefsdb.com/prefsdb.v1.min.js"></script>

Pin a version

prefsdb.v1.min.js always serves the newest client. To load one fixed release that never changes, with a hash your browser checks before running it, use its versioned address:

<script src="https://prefsdb.com/v/1.0.0/prefsdb.v1.min.js"
        integrity="sha384-jyiUM9CYzfqV2JKpdR3dKqq08Lu2aGCMJZ8eB9Mfxq2ldbX2WadD/BsYW+DLwjZq"
        crossorigin="anonymous"></script>

Every release and its hashes (for the add-ons too) are listed in versions.json. Each release also has the readable source next to the minified file, so you can read exactly what you pinned: v/1.0.0/prefsdb.v1.js.

The page must be served over HTTPS, or from http://localhost (or 127.0.0.1) while you develop: getkey()/createkey() refuse to run on a plain http: page anywhere else, since the seed is a password.

Before any read or write operations take place, your page must retrieve the API key/token.

Get API token

Any read or write operation requires a valid API token (a.k.a. API Key).

    [Promise<PrefsDB> p = ] PrefsDB.getkey( name , seed_array [, options])

    [Promise<PrefsDB> p = ] PrefsDB.createkey( name , seed_array [, options])

Both functions require two parameters (name and seed array) and accept an optional "Options" structure:

parameter type description
name string Token ID or name, a plain string identifying the API token (e.g. your app's name)
seed [ ] Seed phrase array, an array of strings containing seed which will be utilized to built the token
options { } /optional/ Additional parameters, e.g. email (required when a new key is created — see below), timeout, onsuccess, onerror. See Options.

These two functions perform the same function: create and return an API key. The only difference is in how they handle a scenario where an existing key is already there.

getkey(): The function will either create a new key or return an existing one.

createkey(): The function will generate and return a new key - if one does not exist. If a key already exists this method will return a failure response.

Which method to use depends solely on your use case and the needs of your app.

Both resolve to a ready-to-use PrefsDB instance — every example in these docs calls it db.

const email    = document.getElementById("email").value;
const password = document.getElementById("password").value;

const db = await PrefsDB.getkey("my-app", [email, password], { email });

if (db.emailVerificationRequired()) {
    // Ask the user to click the link we just emailed them, and wait:
    // this resolves once they have (it checks every few seconds, and
    // straight away when they switch back to this tab).
    showMessage("Check your inbox to confirm your email address.");
    await db.waitForVerification();
}
console.log("API token: %s", db.apitoken());
# -c saves the session cookies that the other calls need.
curl -s -c cookies.txt -G https://prefsdb.com/api/v1/getkey/ \
  --data-urlencode "name=my-app" \
  --data-urlencode "seed=correct horse battery staple" \
  --data-urlencode "namespace=$PREFSDB_NAMESPACE" \
  --data-urlencode "email=you@example.com" \
  -d offline=1
# {"success":true,"token":"38c26...7cb1","message":"New key generated.","emailVerificationRequired":true,...}

KEY=38c26...7cb1   # the "token" from the response

Verify the email address

A brand-new key needs an email address: pass it as the email option (email= over HTTP). PrefsDB sends a verification link to that address, and the new key can't read or write data until the link is clicked. Getting an existing key back doesn't need an email.

emailVerificationRequired() stays true until the link is clicked, also when your user comes back later and getkey() finds the key. await db.waitForVerification() resolves as soon as it's clicked, so your app can carry on by itself; pass { timeout } (milliseconds) or { signal } to stop waiting. Over HTTP, GET /api/v1/verify/status/ with the key answers {"verified": true} once it's done.

The email names your site (for example app.example.com) so your users know which app it's for, and the link opens a page confirming the key is active, with a link back to your site. You can add your app's name and logo to both: see Your site's name and logo.

Tip

Some sites sponsor their users' keys, so no email step is needed at all — see the sponsored() method and the site owner's dashboard. When the email step isn't needed, emailVerificationRequired() is false.

Testing without an inbox

While you build and test your app, use an email address at sandbox.prefsdb.com, such as dev@sandbox.prefsdb.com. That gives you a test key: no email is sent and it works straight away, so you (or an automated test) can go from creating a key to reading and writing data in one go. db.testKey() is true for it.

A test key is only for testing: it stops working a day after it was made (calling getkey() again then gives you a fresh, empty one), it has small limits, and it can't store files. Use a real address for real users.

Changing your site's address

A key belongs to the site it was created on. If your app is served from more than one address (such as example.com and www.example.com), verify both in your dashboard's Sites panel and mark one as the same site as the other, so your users get the same key on both. If your site moves to a new domain, getkey() there won't find your users' existing keys and creates new, empty ones instead. Plan the move ahead with migrateOrigin(): it has to run on the old address, before users reach the new one.

Once you have a token, you are ready to read and write data.

Store data

await db.key("dataKey").write("dataValue");
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" \
  -G https://prefsdb.com/api/v1/write/ --data-urlencode "dataKey=dataValue"

Store large data

.write() handles values of any size up to 1 MB (4 MB on Plus, 8 MB on Pro); it always sends the value as the request body. Over plain HTTP, send a large value the same way rather than in the address:

await db.key("dataKey").write("dataBlob");
# The raw request body becomes the value of the key named in the query string.
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -H "Content-Type: text/plain" \
  --data-binary @blob.txt "https://prefsdb.com/api/v1/write/?dataKey="

Read data

const reply = await db.key("dataKey").read();
let mydata = reply.value;
// do something with your data
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" \
  -G https://prefsdb.com/api/v1/read/ -d "dataKey="
# {"value":"dataValue","uid":"12345","modifiedt":"2026-09-24 12:00:00","count":1,"status":"success","success":true,...}

Using the HTTP API directly

Every example in these docs has a cURL tab with the raw HTTP equivalent. They all assume the getkey call above has been made, so that:

  • $KEY holds the key from its token field, sent back as X-Authorization: Token $KEY (Authorization: Bearer $KEY works too);
  • cookies.txt holds the session cookies it set. -b cookies.txt sends them. With offline=1 they're good for reads, writes and deletes for 8 hours. Key rotation and file uploads/downloads need a getkey call from the last 60 seconds.

The same session is also in the getkey response, as session.token (and session.offlineToken with offline=1). An HTTP client that doesn't keep cookies, or a web page on your own site calling the API with fetch, sends it as a header instead: X-Prefs-Session: <session.token> (and X-Prefs-Offline-Session: <session.offlineToken>). Browsers never send our cookies from another site, so from a web page the header is the only way. The JavaScript client does this for you, and gets a new session by itself when one runs out.

Every endpoint, parameter, response and error code is also described in a machine-readable file, openapi.json (OpenAPI 3.1), which API tools and AI assistants can read directly.

Without a browser there's no Origin header to keep your keys apart from other sites' keys, so pass a namespace: a long random value you generate once (e.g. openssl rand -hex 32) and keep secret, like the seed. A key created with cURL is separate from the ones your web page creates, even with the same name and seed: the browser's origin is part of what identifies a key, and the JavaScript client hashes the seed array before sending it.

If you have a PrefsDB account and your server only needs a fixed key, you can skip getkey, the seed and the namespace altogether: create an API key in your dashboard, keep it with your server's other secrets, and send it as X-Authorization: Token <key>. A dashboard key works on its own, with no cookies and no time limit. You only need getkey when your server creates keys from a name and seed, for example one key per user. A dashboard key can also be made read-only, limited to one project, or set to expire.

A few things to know about dashboard keys:

  • A Live key starts out suspended, so it can't be used by accident. Activate it in the dashboard (click its lock icon) when you're ready. A Development key works straight away.
  • An account can have 25 keys at a time and create up to 20 new ones a day; paid plans allow more. A deleted key doesn't count toward the 25.
  • A deleted key stops working at once, but you can restore it from the dashboard for 30 days. After that it's removed together with everything stored under it. You can download a key's data from the dashboard at any time, including after deleting it.
  • Dashboard keys are for your own apps and servers. Don't share or resell them: an account that hands keys out to others can be suspended, and then none of its keys work.

If you have an account, use an app credential for that instead of a namespace: create one in your dashboard's App Credentials panel and pass it as appcred wherever you'd pass namespace (never both). It keeps your server's keys apart just like a namespace, with two differences: you don't have to come up with a value, and a mistyped or revoked credential gets an error instead of quietly giving you a new, empty key. You can see and revoke your credentials in the dashboard.

// Set once, e.g. from an environment variable.
// Every getkey(), createkey() and rotate() call sends it.
PrefsDB.APPCRED = process.env.PREFSDB_APPCRED;
const db = await PrefsDB.getkey("my-app", [userId], { email: userEmail });
curl -s -c cookies.txt -G https://prefsdb.com/api/v1/getkey/ \
  --data-urlencode "name=my-app" \
  --data-urlencode "seed=$USER_ID" \
  --data-urlencode "appcred=$PREFSDB_APPCRED" \
  --data-urlencode "email=you@example.com"

Revoking a credential stops new getkey calls through it, including yours, but keys already created with it keep working. To move keys onto a different credential, use migrateAppcred() before revoking the old one.

Notes

  1. You may keep and re-use the same key for all subsequent queries to keep your items grouped together, whether saving or retrieving them.
  2. Use grouping parameters such as 'project', 'domain', 'subdomain', or 'list' to help with organizing your data attached to your API key.
  3. Keys from getkey are free to create, one per user if you like; each key has its own request and storage limits. Dashboard keys are limited per account (see above).
  4. All timestamps are UTC