Getting Started
After creating your project in Skapi, connect it to your frontend.
Your frontend is the part users see, such as pages, buttons, and forms. It can be plain HTML or a JavaScript framework like Vue or React.
Skapi works with vanilla HTML and modern JavaScript frameworks (for example Vue, React, and Angular).
To use Skapi, import the library and initialize it with your project ID.
For HTML Projects
For vanilla HTML projects, import Skapi using a script tag and initialize the library as shown below. Initialize the Skapi class in the HTML <head> of each page that uses Skapi. When you initialize the class, use the exact project ID from your Skapi dashboard.
<!-- 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 whole string with your actual project ID from your Skapi dashboard after you create a project, so the line reads like this:
const skapi = new Skapi("abc123defg456hij78-9klmnop012qrstu345vwxyz");Every example in these docs uses the same "<Project ID>" placeholder, so replace it wherever you copy one.
The project ID is a single token that identifies your project and its owner.
Example format: "xxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxx"
For BunnyQuery users
A BunnyQuery project ID is a Skapi project ID; use it as-is.
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.
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.
