Getting Started
Skapi is a serverless backend API for your web application.
To enable backend features, first create a project at skapi.com.
Creating a Project
- Sign up for an account at skapi.com.
- Log in, name your project, and choose a region. Click Create.
For BunnyQuery users
BunnyQuery projects are fully compatible with Skapi. Your project will appear in both your BunnyQuery and Skapi project lists.
For HTML Projects
For vanilla HTML projects, load Skapi using a script tag and initialize the library as shown below. Add the Skapi script and initialize the Skapi class in the <head> of each page that uses Skapi. Use the exact Project ID of your Skapi project when initializing the library.
<!-- index.html -->
<!DOCTYPE html>
<script src="https://cdn.jsdelivr.net/npm/skapi-js@latest/dist/skapi.js"></script>
<script>
// Replace "<Project ID>" with your actual project ID
const skapi = new Skapi("<Project ID>");
</script>Replace the placeholder
<Project ID> is a placeholder, including the angle brackets.
Replace the entire string with your actual Project ID from the Skapi dashboard. For example:
const skapi = new Skapi("abc123defg456hij78-9klmnop012qrstu345vwxyz");Every example in these docs uses the same "<Project ID>" placeholder. Replace it wherever you copy an example.
The Project ID is a unique identifier for your Skapi project.
Example format: "xxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxx"
For SPA Projects
To use Skapi in a Single Page Application (SPA) such as Vue, React, or Angular, install skapi-js with npm.
$ npm i skapi-jsThen import the library in your main JavaScript file:
// main.js
import { Skapi } from "skapi-js";
const skapi = new Skapi("<Project ID>");
export { skapi }
// You can now import skapi from anywhere in your project.For TypeScript Projects
Skapi includes TypeScript support, so you can import both the class and related types.
import { Skapi } from 'skapi-js';
import type { RecordData, DatabaseResponse } from 'skapi-js';
const skapi = new Skapi("<Project ID>");
let databaseRecords: DatabaseResponse<RecordData>;Node.js (CommonJS)
To use Skapi in Node.js (CommonJS), import the library as shown below:
const { Skapi } = require('skapi-js');
const skapi = new Skapi("<Project ID>");Node.js (ESM)
import { Skapi } from 'skapi-js';
const skapi = new Skapi("<Project ID>");Note: When running Skapi in Node.js, browser-specific features such as WebSocket, WebRTC, and Notifications are not available.
Get Connection Information
After your client connects to Skapi, call getConnectionInfo() to retrieve connection details.
<!-- index.html -->
<!DOCTYPE html>
<script src="https://cdn.jsdelivr.net/npm/skapi-js@latest/dist/skapi.js"></script>
<script>
const skapi = new Skapi("<Project ID>");
</script>
<script>
skapi.getConnectionInfo().then(info => {
console.log(info);
/*
Returns:
{
project_id: "Public project ID of the connected project",
user_ip: "Connected user's IP address",
user_agent: "Connected user agent",
user_location: "Connected user's country code",
service_name: "Your Project Name",
service_description: "Your project description",
version: 'x.x.x', // Skapi library version
ai_agent: "AI agent instructions set for the project",
conf: {
freeze_database: boolean, // Database is read only
prevent_signup: boolean, // Signup is blocked
prevent_inquiry: boolean, // Inquiry is blocked
prevent_anonymous: boolean // Anonymous users cannot write to the database
}
}
*/
window.alert(`Connected to ${info.service_name}`);
});
</script>import { skapi } from '../location/of/your/main.js';
skapi.getConnectionInfo().then(info => {
console.log(info);
/*
Returns:
{
project_id: "Public project ID of the connected project",
user_ip: "Connected user's IP address",
user_agent: "Connected user agent",
user_location: "Connected user's country code",
service_name: "Your Project Name",
service_description: "Your project description",
version: 'x.x.x', // Skapi library version
ai_agent: "AI agent instructions set for the project",
conf: {
freeze_database: boolean, // Database is read only
prevent_signup: boolean, // Signup is blocked
prevent_inquiry: boolean, // Inquiry is blocked
prevent_anonymous: boolean // Anonymous users cannot write to the database
}
}
*/
window.alert(`Connected to ${info.service_name}`);
});Advanced Settings
You can pass additional options when initializing the Skapi class.
new Skapi(...)
class Skapi {
constructor(
project_id: string, // Skapi project ID. The legacy service ID + owner ID pair is still accepted.
options?: {
autoLogin?: boolean; // Default: true
refetchServiceInfo?: boolean;// Default: false. Bypasses cached project info and always fetch new project info on load.
requestBatchSize?: number; // Default: 30. Maximum number of requests processed per batch.
encryption?: boolean | { // Default: false. Encrypts the data of private records in the browser. Can only be set here, on initialization. HTTPS required.
iterations?: number; // Default: 600000. PBKDF2 cost. Minimum 100000.
minPasswordLength?: number; // Default: 0 (off). Refuses to set up encryption for a shorter password.
persistDevice?: boolean; // Default: true. Stays unlocked across page reloads on that device.
recovery?: 'code' | 'none'; // Default: 'code'. Issues a one-time recovery code.
trustPolicy?: 'tofu' | 'strict'; // Default: 'tofu'. How a recipient's public key is trusted when sharing.
withheld?: 'null' | 'sentinel'; // Default: 'null'. What data is set to when a record cannot be decrypted.
table?: string; // Default: '__skapi__keyring'. Reserved table that stores the user's keyring.
};
eventListener?: {
onLogin?: (user: UserProfile | null) => void; // Fires on initial page load (after Skapi initializes), on login/logout, and when a session expires. The callback receives a UserProfile object if the user is logged in; otherwise, it receives null.
onUserUpdate?: (user: UserProfile | null) => void; // Fires on initial page load (after Skapi initializes), on login/logout, when a session expires, and when the user's profile is updated. The callback receives a UserProfile object if the user is logged in; otherwise, it receives null.
onBatchProcess?: (process: {
batchToProcess: number; // Number of batches left to process
itemsToProcess: number; // Number of items left to process
completed: any[]; // Results completed in this batch
}) => void;
}
}) {
...
}
...
}Options overview:
autoLogin(boolean, default: true)- Automatically restores the user's session on page load.
- See: Auto Login
requestBatchSize(number, default: 30)- Maximum number of requests processed per batch.
encryption(boolean | object, default: false)- Encrypts the
dataof the records saved toaccess_group: 'private', in the browser, before it reaches the database. The contents of the files attached to those records are encrypted as well. - This only takes effect when it is set here, when the Skapi class is initialized. There is no method that turns encryption on afterwards, so when this option is left out, the instance saves the
dataof every record as plain text for its entire lifetime. - Enabling it later does not go back and encrypt the records that were already saved as plain text.
- Setting it to
trueuses the default settings. Pass an object to change them:iterations(number, default: 600000): PBKDF2 cost of deriving the key from the user's password. Minimum 100000.minPasswordLength(number, default: 0, off): refuses to set up encryption for a password shorter than this. The strength of the encryption is capped by the user's password, so it is worth setting.persistDevice(boolean, default: true): keeps encryption unlocked across page reloads on that device.recovery('code' | 'none', default: 'code'): issues a one-time recovery code, which is the only way for the user to reach their data again after a password reset.trustPolicy('tofu' | 'strict', default: 'tofu'): how a recipient's public key is trusted when a record is shared.'strict'requires the key to be pinned before the first share.withheld('null' | 'sentinel', default: 'null'): whatdatais set to when a record cannot be decrypted.'sentinel'returns a placeholder object carrying the reason instead ofnull.table(string, default: '__skapi__keyring'): the reserved table that stores the user's keyring.
- See: Encrypting Private Record Data
- Encrypts the
eventListener(callbacks for key events)onLogin(user: UserProfile | null)- Fires on initial page load (after Skapi initializes), on login/logout, and when a session expires. The callback receives a
UserProfileobject if the user is logged in; otherwise, it receivesnull. - See: Listening to Login/Logout Status
- Fires on initial page load (after Skapi initializes), on login/logout, and when a session expires. The callback receives a
onUserUpdate(user: UserProfile | null)- Fires on initial page load (after Skapi initializes), on login/logout, when a session expires, and when the user's profile is updated. The callback receives a
UserProfileobject if the user is logged in; otherwise, it receivesnull. - See: Listening to User Profile Updates
- Fires on initial page load (after Skapi initializes), on login/logout, when a session expires, and when the user's profile is updated. The callback receives a
onBatchProcess(process)- Fires each time Skapi completes processing a request batch.
Type reference: See UserProfile.
