Interactive Tutorials SDK
Add interactive step-by-step tutorials to your product. Your users learn by doing, right inside your app.
Quick Start (2 minutes)
Paste the snippet below in the head tag of your site:
<script
src="https://app.stepyo.com.br/sdk.js"
data-api-key="YOUR_API_KEY"
data-lang="en"
async
></script>Done. The help widget appears automatically in the bottom-right corner.
Tip: use a versioned URL like [email protected] to pin a specific version.
Installation Methods
Script tag (recommended)
The simplest approach. Works with any framework or static site.
<script
src="https://app.stepyo.com.br/sdk.js"
data-api-key="YOUR_API_KEY"
data-lang="en"
data-position="bottom-right"
data-color="#EC4899"
data-button-text="Need help?"
data-title="Help Center"
data-icon="help"
data-user-id="user_123"
data-user-email="[email protected]"
async
></script>React / Next.js
Create a client component that loads the SDK:
// components/StepyoWidget.tsx
'use client';
import { useEffect } from 'react';
export function StepyoWidget() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://app.stepyo.com.br/sdk.js';
script.async = true;
script.dataset.apiKey = process.env.NEXT_PUBLIC_STEPYO_KEY!;
script.dataset.lang = 'en';
document.head.appendChild(script);
return () => {
(window as any).Stepyo?.destroy();
script.remove();
};
}, []);
return null;
}
// In your layout: <StepyoWidget />Vue / Nuxt
Use a composable to load the SDK:
<!-- StepyoWidget.vue -->
<script setup>
import { onMounted, onUnmounted } from 'vue';
const props = defineProps({ apiKey: String });
onMounted(() => {
const s = document.createElement('script');
s.src = 'https://app.stepyo.com.br/sdk.js';
s.dataset.apiKey = props.apiKey;
s.async = true;
document.head.appendChild(s);
});
onUnmounted(() => window.Stepyo?.destroy());
</script>npm package
Install the SDK via npm for better TypeScript support and tree-shaking:
npm install @stepyo/sdkThen use it in your code:
import Stepyo from '@stepyo/sdk';
Stepyo.init({
apiKey: 'your_api_key_here',
lang: 'en',
});You can check the current SDK version at runtime with Stepyo.version.
Server-side SDKs
Use the server SDKs to interact with the Stepyo API from your backend. Useful for triggering flows, tracking events, and handling webhooks.
Node.js
npm install @stepyo/serverPython
pip install stepyoNode.js
Install:
npm install @stepyo/serverUsage:
import { StepyoServer } from '@stepyo/server';
const stepyo = new StepyoServer({
apiKey: process.env.STEPYO_SECRET_KEY,
});
// List all active flows
const flows = await stepyo.listFlows();
// Get a specific flow with steps
const flow = await stepyo.getFlow('welcome-tour');
// AI-powered flow suggestion
const suggestion = await stepyo.ask('How do I create a report?');
// Track a custom event
await stepyo.trackEvent({
name: 'onboarding_completed',
userId: 'user_123',
properties: { plan: 'pro' },
});Python
Install:
pip install stepyoUsage:
from stepyo import StepyoServer
stepyo = StepyoServer(api_key="your_secret_key")
# List all active flows
flows = stepyo.list_flows()
# Get a specific flow with steps
flow = stepyo.get_flow("welcome-tour")
# AI-powered flow suggestion
suggestion = stepyo.ask("How do I create a report?")
# Track a custom event
stepyo.track_event(
name="onboarding_completed",
user_id="user_123",
properties={"plan": "pro"},
)Framework integration
Handle webhooks in your framework of choice:
# Flask
from flask import Flask, request, jsonify
from stepyo import StepyoServer
app = Flask(__name__)
stepyo = StepyoServer(api_key="your_secret_key")
@app.route("/webhooks/stepyo", methods=["POST"])
def handle_webhook():
signature = request.headers.get("X-Stepyo-Signature", "")
if not stepyo.verify_webhook(request.data, signature):
return jsonify({"error": "Invalid signature"}), 401
event = request.json
print(f"Received: {event['event']}")
return jsonify({"ok": True})
# FastAPI
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
@app.post("/webhooks/stepyo")
async def handle_webhook(request: Request):
body = await request.body()
signature = request.headers.get("X-Stepyo-Signature", "")
if not stepyo.verify_webhook(body, signature):
raise HTTPException(status_code=401)
event = await request.json()
return {"ok": True}
# Django
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def stepyo_webhook(request):
signature = request.headers.get("X-Stepyo-Signature", "")
if not stepyo.verify_webhook(request.body, signature):
return JsonResponse({"error": "Invalid signature"}, status=401)
import json
event = json.loads(request.body)
return JsonResponse({"ok": True})JavaScript API Reference
All methods are available on window.Stepyo:
Stepyo.init(config)
Initializes the SDK manually (alternative to auto-init via script tag).
Stepyo.init({
apiKey: 'your_api_key_here',
lang: 'en', // 'en' | 'pt-BR'
position: 'bottom-right', // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
primaryColor: '#EC4899', // hex
buttonText: 'Help', // button label (empty = icon only)
panelTitle: 'Tutorials',
buttonIcon: 'help', // 'help'|'chat'|'book'|'zap'|'sparkles'|'headphones' or URL
});Stepyo.identify(user)
Associates SDK events with the user in your app. Call after login.
Stepyo.identify({
userId: 'user_123',
email: '[email protected]',
name: 'Jane Smith',
traits: { role: 'admin', plan: 'pro' }
});Stepyo.startFlow(flowKey)
Starts a specific tutorial by key. Ideal for contextual onboarding.
// Trigger tutorial when user creates an account
Stepyo.startFlow('welcome-tour');Stepyo.openPanel() / Stepyo.closePanel()
Opens or closes the tutorials panel programmatically.
Stepyo.isReady()
Returns true when the SDK has finished loading.
Stepyo.on(event, callback) / Stepyo.off(event, callback)
Listen to SDK events.
Stepyo.on('flow:completed', (data) => {
console.log('Tutorial completed:', data.flowKey);
// Mark onboarding as complete in your backend
});
Stepyo.on('ready', () => {
// SDK loaded, safe to use startFlow
});Stepyo.destroy()
Removes the widget and cleans up listeners. Use in SPAs when unmounting the component.
Stepyo.version
Returns the current SDK version string (e.g. "2.0.0").
console.log(Stepyo.version); // "2.0.0"Configuration options
| Attribute | Type | Description |
|---|---|---|
data-api-key | string | API key (required) |
data-lang | en | pt-BR | Language (default: en) |
data-position | string | Button position |
data-color | hex | Widget primary color (hex) |
data-button-text | string | Button label (empty = icon only) |
data-title | string | Panel title |
data-icon | string | Preset icon or image URL |
data-user-id | string | User ID |
data-user-email | string | User email |
data-user-name | string | User name |
Events
| Event | Data | When fired |
|---|---|---|
ready | - | SDK initialized |
flow:started | {flowKey, flowName} | Tutorial started |
flow:completed | {flowKey} | Tutorial completed |
flow:cancelled | {flowKey, lastStep} | User cancelled |
step:changed | {flowKey, stepIndex, totalSteps} | Advanced/went back a step |
step:failed | {flowKey, stepIndex, error} | Element not found |
panel:opened | - | Tutorials panel opened |
panel:closed | - | Panel closed |
Deep linking
Open a specific tutorial via URL:
https://yourapp.com/dashboard?stepyo-flow=welcome-tourWebhooks
Webhooks let your server receive real-time notifications when events happen in the SDK. Configure webhooks in the dashboard or via the REST API.
How to configure
Go to Settings > SDK > Webhooks in your dashboard, or use the REST API endpoints below.
Available events
Subscribe to specific events or use * to receive all:
| Event | Description |
|---|---|
flow_started | A tutorial was started |
flow_completed | A tutorial was completed |
flow_cancelled | A tutorial was cancelled |
step_failed | A step element was not found |
chat_escalated | User escalated from AI chat |
widget_opened | The widget was opened |
* | All events |
Payload example
{
"id": "evt_abc123",
"event": "flow_completed",
"timestamp": "2026-03-19T12:00:00Z",
"data": {
"flow_key": "welcome-tour",
"flow_name": "Welcome Tour",
"user_id": "user_123",
"user_email": "[email protected]",
"duration_ms": 45200
},
"workspace_id": "ws_xyz"
}Signature verification
Every webhook request includes a X-Stepyo-Signature header containing an HMAC SHA-256 signature. Verify it to ensure the request came from Stepyo.
Node.js verification
import crypto from 'crypto';
function verifyWebhookSignature(body, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(body, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
// Express middleware
app.post('/webhooks/stepyo', express.raw({ type: '*/*' }), (req, res) => {
const sig = req.headers['x-stepyo-signature'];
if (!verifyWebhookSignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body);
console.log('Event:', event.event);
res.json({ ok: true });
});Python verification
import hmac
import hashlib
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)Auto-disable behavior
If your endpoint returns a non-2xx status code for 10 consecutive deliveries, the webhook is automatically disabled. You can re-enable it in the dashboard.
Retry policy
Failed deliveries are retried up to 3 times with exponential backoff (1 min, 5 min, 30 min).
REST API Reference
All endpoints are relative to https://app.stepyo.com.br. API key endpoints use the x-stepyo-key header. Session endpoints require an authenticated browser session.
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/api/sdk/init | POST | API Key | Initialize SDK session |
/api/sdk/flows | GET | API Key | List active flows |
/api/sdk/flows/:key | GET | API Key | Get flow with steps |
/api/sdk/ask | POST | API Key | AI flow suggestion |
/api/sdk/events | POST | API Key | Track event |
/api/sdk/chat | POST | API Key | Chat (SSE stream) |
/api/sdk/webhooks | GET | Session | List webhooks |
/api/sdk/webhooks | POST | Session | Create webhook |
/api/sdk/webhooks/:id | PATCH | Session | Update webhook |
/api/sdk/webhooks/:id | DELETE | Session | Delete webhook |
/api/sdk/webhooks/:id/test | POST | Session | Test webhook delivery |
/api/sdk/webhooks/:id/logs | GET | Session | View delivery logs |
Authentication
For API-key-authenticated endpoints, include your key in the header:
x-stepyo-key: sk_live_abc123...Rate limits
Default: 60 requests/minute per API key. Configurable per key in the dashboard. When exceeded, the API returns 429 Too Many Requests.
Response format
All responses are JSON. Successful responses include the data directly. Errors follow this format:
{
"error": "Rate limit exceeded",
"code": "RATE_LIMITED",
"retryAfter": 30
}Versioning
Latest (always up to date)
sdk.js always points to the latest stable version.
<script src="https://app.stepyo.com.br/sdk.js" ...></script>Pinned version
Pin a specific version to avoid unexpected changes:
<script src="https://app.stepyo.com.br/[email protected]" ...></script>Runtime version check
Check the version at runtime:
if (Stepyo.version !== '2.0.0') {
console.warn('Unexpected SDK version:', Stepyo.version);
}Breaking change policy
We follow semantic versioning. Breaking changes only happen in major versions and are announced at least 30 days in advance via email and the dashboard.
Security
API Keys
- Keys are hashed with SHA-256 on the server (never stored as plain text)
- The full key is shown only once (at creation)
- Keys can be disabled or deleted at any time
Allowed domains
- Configure which domains can use your API key
- Supports wildcards: *.yourdomain.com
- Requests from unauthorized domains are blocked (CORS)
Rate limiting
- Default: 60 requests/minute per key
- Configurable per key in the dashboard
Webhook signatures
Every webhook delivery is signed with HMAC SHA-256 using your webhook secret. Always verify signatures before processing payloads.
FAQ
The bundle is ~12KB gzip. It loads asynchronously (async) and does not block rendering. Uses Shadow DOM for full CSS isolation.
Yes. The SDK detects client-side navigation and persists tutorial state across pages via sessionStorage.
Use the Stepyo Chrome extension to record tutorials in your product. Then convert them to a flow and activate for the SDK in the dashboard.
Yes. Use Stepyo.startFlow('key') to trigger tutorials programmatically. To hide the floating button, do not set data-button-text and use CSS to hide it if needed.
The SDK only sends the data you pass via identify(). No personal data is collected automatically. Events are stored for 90 days and accessible only through your dashboard.
Configure a webhook in Settings > SDK > Webhooks. Your server will receive POST requests with event payloads whenever SDK events occur. See the Webhooks section for details.
Yes. We offer official SDKs for Node.js (npm install @stepyo/server) and Python (pip install stepyo). See the Server-side SDKs section for usage examples.
Each webhook request includes an X-Stepyo-Signature header. Compute an HMAC SHA-256 of the request body using your webhook secret and compare. See the Webhooks section for code examples.
Stepyo retries failed deliveries up to 3 times with exponential backoff. After 10 consecutive failures, the webhook is automatically disabled. You can re-enable it from the dashboard.