luqta-sdk
v1.0.16
Published
Luqta SDK - Official JavaScript/TypeScript SDK for Luqta API integration. Easy-to-use client for React, Angular, Vue, Next.js, Svelte, and vanilla JavaScript. Supports CDN and npm installation with TypeScript support, authentication, user management, and
Maintainers
Keywords
Readme
Luqta Web SDK
Official JavaScript/TypeScript SDK for integrating Luqta contest management, user engagement, and gamification features into web applications.
Quick Start (5 Minutes)
Step 1: Install the SDK
npm install luqta-sdkOr use CDN:
<script src="https://unpkg.com/luqta-sdk@latest/dist/luqta-sdk.min.js"></script>Step 2: Add a Container Element
<div id="luqta-container"></div>Step 3: Initialize and Render
import { LuqtaClient } from 'luqta-sdk';
const client = new LuqtaClient({
mode: 'preconfigured',
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID',
containerId: 'luqta-container',
user: { email: '[email protected]' }
});
await client.render();That's it! The SDK will display a complete contest UI with all features.
Table of Contents
- Quick Start
- Features
- Installation
- Usage Modes
- Complete Examples
- Configuration Options
- API Reference
- Level Types
- Error Handling
- TypeScript Support
- FAQ
Features
| Feature | Description | |---------|-------------| | Pre-built UI | Complete contest UI with zero design work | | Custom Branding | Match your app's colors, fonts, and logo | | 5 Level Types | Text, QR Code, Link, Image Upload, Quiz | | QR Scanner | Built-in camera scanner for QR codes | | Image Upload | File picker with preview | | Quiz System | Multi-question flow with results | | Bilingual | English and Arabic with RTL support | | TypeScript | Full type definitions included | | Zero Dependencies | Lightweight core library |
Installation
Option 1: npm (Recommended)
npm install luqta-sdkimport { LuqtaClient } from 'luqta-sdk';Option 2: CDN
<!-- Add before </body> -->
<script src="https://unpkg.com/luqta-sdk@latest/dist/luqta-sdk.min.js"></script>
<script>
const client = new LuqtaSDK.LuqtaClient({
// your config
});
</script>Usage Modes
1. Pre-configured UI Mode (Recommended)
Best for: Quick integration with minimal code. The SDK handles all UI, screens, and user flows.
Option A: All-in-One Initialization
<!DOCTYPE html>
<html>
<head>
<title>My App with Luqta</title>
</head>
<body>
<!-- Container where SDK UI will appear -->
<div id="luqta-container" style="width: 100%; max-width: 800px; margin: 0 auto;"></div>
<script src="https://unpkg.com/luqta-sdk@latest/dist/luqta-sdk.min.js"></script>
<script>
async function initLuqta() {
const client = new LuqtaSDK.LuqtaClient({
mode: 'preconfigured',
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID',
containerId: 'luqta-container',
user: { email: '[email protected]' }
});
await client.render();
}
initLuqta();
</script>
</body>
</html>Option B: Step-by-Step Initialization (More Control)
For more control over the initialization process, use separate steps:
// Step 1: Create client with credentials
const client = new LuqtaSDK.LuqtaClient({
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID',
user: { email: '[email protected]' }
});
// Step 2: Initialize SDK (validates credentials, fetches initial data)
const result = await client.initializeSdk();
console.log('Found contests:', result.contests.data?.items?.length);
// Step 3: Configure UI settings (optional - call anytime before render)
client.configure({
containerId: 'luqta-container',
branding: {
primaryColor: '#5304fb',
secondaryColor: '#8f67fd',
appName: 'My App'
},
locale: 'en',
rtl: false,
onAction: (action) => console.log('Action:', action),
onError: (error) => console.error('Error:', error)
});
// Step 4: Render the UI
await client.render();With Custom Branding
const client = new LuqtaClient({
mode: 'preconfigured',
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID',
containerId: 'luqta-container',
user: { email: '[email protected]' },
// Customize to match your brand
branding: {
primaryColor: '#5304fb', // Main buttons and links
secondaryColor: '#8f67fd', // Gradients
backgroundColor: '#ffffff', // Page background
textColor: '#111827', // Text color
logoUrl: 'https://yoursite.com/logo.png',
appName: 'My App',
borderRadius: 12, // Rounded corners (px)
fontFamily: 'Inter, sans-serif'
},
// Language settings
locale: 'en', // 'en' or 'ar'
rtl: false, // true for Arabic
// Track user actions
onAction: (action) => {
console.log('User action:', action.type, action.data);
},
// Handle errors
onError: (error) => {
console.error('SDK error:', error.message);
}
});
await client.render();What the Pre-configured UI Includes
- Contest List - Grid of available contests with banners and status
- Contest Detail - Full contest info with levels, prizes, and progress
- Level Modals - Different UI for each level type:
- Text: Input field
- QR: Camera scanner with "Scan Now" button
- Link: Opens link in new tab
- Image: Upload area with preview
- Quiz: Question flow with options
- Congratulation Screens - Level and contest completion celebrations
- Progress Tracking - Visual progress bars and completed badges
2. Custom UI Mode (API Only)
Best for: Building your own UI design while using SDK for API calls.
Step 1: Create Client
import { LuqtaClient } from 'luqta-sdk';
const client = new LuqtaClient({
mode: 'custom',
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID',
user: { email: '[email protected]' }
});Step 2: Initialize User
// Required before any user-specific API calls
await client.initializeUser();Step 3: Use API Methods
// Get all contests
const contests = await client.contests.getAll({ page: 1, per_page: 10 });
console.log(contests.data.items);
// Participate in a contest
await client.contests.participate(123);
// Get contest progress with levels
const progress = await client.contests.getProgress(123);
console.log(progress.data.levels);
// Complete a text level
await client.levels.complete(456, { textContent: 'my answer' });
// Complete a QR level
await client.levels.complete(456, { qrCode: 'scanned_data' });
// Complete an image level
await client.levels.completeWithImage(456, 'https://example.com/photo.jpg');
// Start and complete a quiz
const quiz = await client.quiz.start(789);
await client.quiz.submitAnswer(quiz.data.attempt.id, 1, 101);
const results = await client.quiz.submit(quiz.data.attempt.id);Complete Examples
Example 1: React Integration
import { useEffect, useState } from 'react';
import { LuqtaClient } from 'luqta-sdk';
function LuqtaContests() {
const [client, setClient] = useState(null);
useEffect(() => {
const initClient = async () => {
const luqtaClient = new LuqtaClient({
mode: 'preconfigured',
apiKey: process.env.REACT_APP_LUQTA_API_KEY,
appId: process.env.REACT_APP_LUQTA_APP_ID,
containerId: 'luqta-container',
user: { email: '[email protected]' },
branding: {
primaryColor: '#5304fb'
},
onAction: (action) => {
if (action.type === 'level_completed') {
console.log('Points earned:', action.data.points_earned);
}
}
});
await luqtaClient.render();
setClient(luqtaClient);
};
initClient();
}, []);
return <div id="luqta-container" style={{ minHeight: '600px' }} />;
}
export default LuqtaContests;Example 2: Vue.js Integration
<template>
<div id="luqta-container" style="min-height: 600px;"></div>
</template>
<script>
import { LuqtaClient } from 'luqta-sdk';
export default {
name: 'LuqtaContests',
data() {
return {
client: null
};
},
async mounted() {
this.client = new LuqtaClient({
mode: 'preconfigured',
apiKey: import.meta.env.VITE_LUQTA_API_KEY,
appId: import.meta.env.VITE_LUQTA_APP_ID,
containerId: 'luqta-container',
user: { email: '[email protected]' }
});
await this.client.render();
}
};
</script>Example 3: Next.js Integration
'use client';
import { useEffect } from 'react';
export default function LuqtaPage() {
useEffect(() => {
const initLuqta = async () => {
// Dynamic import for client-side only
const { LuqtaClient } = await import('luqta-sdk');
const client = new LuqtaClient({
mode: 'preconfigured',
apiKey: process.env.NEXT_PUBLIC_LUQTA_API_KEY,
appId: process.env.NEXT_PUBLIC_LUQTA_APP_ID,
containerId: 'luqta-container',
user: { email: '[email protected]' }
});
await client.render();
};
initLuqta();
}, []);
return <div id="luqta-container" style={{ minHeight: '600px' }} />;
}Example 4: Vanilla JavaScript (Full Page)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Luqta Contests</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: system-ui, sans-serif; background: #f5f5f5; }
#luqta-container {
max-width: 900px;
margin: 20px auto;
background: white;
border-radius: 16px;
min-height: 80vh;
}
</style>
</head>
<body>
<div id="luqta-container"></div>
<script src="https://unpkg.com/luqta-sdk@latest/dist/luqta-sdk.min.js"></script>
<script>
(async function() {
try {
const client = new LuqtaSDK.LuqtaClient({
mode: 'preconfigured',
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID',
containerId: 'luqta-container',
user: { email: '[email protected]' },
branding: {
primaryColor: '#5304fb',
appName: 'My Contests'
},
locale: 'en',
onAction: function(action) {
console.log('Action:', action.type);
if (action.type === 'contest_joined') {
console.log('Joined contest:', action.data.contest_name);
}
if (action.type === 'level_completed') {
console.log('Earned points:', action.data.points_earned);
}
}
});
await client.render();
console.log('Luqta SDK loaded successfully!');
} catch (error) {
console.error('Failed to load Luqta SDK:', error);
}
})();
</script>
</body>
</html>Example 5: Arabic RTL Layout
const client = new LuqtaClient({
mode: 'preconfigured',
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID',
containerId: 'luqta-container',
user: { email: '[email protected]' },
locale: 'ar', // Arabic language
rtl: true // Right-to-left layout
});
await client.render();Example 6: Step-by-Step with User Sync (New Users)
When integrating with your app where users might not exist in Luqta yet:
const client = new LuqtaSDK.LuqtaClient({
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID'
});
// Step 1: Initialize SDK (no user needed)
await client.initializeSdk();
console.log('SDK ready!');
// Step 2: Set user from your app's auth
client.setUser({
email: currentUser.email,
phone_number: currentUser.phone
});
// Step 3: Try to initialize user
try {
await client.initializeUser();
} catch (error) {
if (error.code === 'USER_NOT_SYNCED') {
// User doesn't exist in Luqta - sync them first
await client.syncAndInitializeUser({
name: currentUser.name,
email: currentUser.email,
phone_number: currentUser.phone,
gender: currentUser.gender,
country: currentUser.country
});
} else {
throw error;
}
}
// Step 4: Configure and render UI
client.configure({
containerId: 'luqta-container',
branding: { primaryColor: '#5304fb' }
});
await client.render();Configuration Options
Required Options
| Option | Type | Description |
|--------|------|-------------|
| apiKey | string | Your Luqta API key |
| appId | string | Your Luqta application ID |
Pre-configured Mode Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| mode | string | - | Must be 'preconfigured' |
| containerId | string | - | ID of the HTML container element |
| user | object | - | User identification (email or phone) |
| branding | object | - | Custom branding options (see below) |
| locale | string | 'en' | Language: 'en' or 'ar' |
| rtl | boolean | false | Enable right-to-left layout |
| onAction | function | - | Callback for user actions |
| onError | function | - | Callback for errors |
Branding Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| primaryColor | string | '#5304fb' | Main action color |
| secondaryColor | string | '#8f67fd' | Secondary/gradient color |
| backgroundColor | string | '#ffffff' | Background color |
| textColor | string | '#111827' | Main text color |
| logoUrl | string | - | URL to your logo image |
| appName | string | - | App name displayed in header |
| borderRadius | number | 8 | Border radius in pixels |
| fontFamily | string | 'system-ui' | Font family |
User Identification
Provide at least one:
user: {
email: '[email protected]'
}
// OR
user: {
phone_number: '+923001234567' // E.164 format
}
// OR both
user: {
email: '[email protected]',
phone_number: '+923001234567'
}API Reference
SDK Initialization Methods
// Initialize SDK (validates API key and App ID, fetches initial data)
const result = await client.initializeSdk();
// Returns: { success: true, contests: PaginatedResponse<Contest> }
// Check if SDK is ready
const sdkReady = client.isSdkReady();
// Fetch contests (after SDK initialization)
const contests = await client.fetchContests({ page: 1, per_page: 10 });UI Configuration Methods
// Configure UI settings (for step-by-step initialization)
client.configure({
containerId: 'luqta-container',
branding: {
primaryColor: '#5304fb',
secondaryColor: '#8f67fd',
backgroundColor: '#ffffff',
textColor: '#111827',
logoUrl: 'https://example.com/logo.png',
appName: 'My App',
borderRadius: 12,
fontFamily: 'Inter, sans-serif'
},
locale: 'en',
rtl: false,
screens: ['contests', 'quizzes', 'rewards', 'profile'],
onAction: (action) => console.log(action),
onError: (error) => console.error(error)
});
// Update branding after initialization
client.setBranding({
primaryColor: '#ff5722',
logoUrl: 'https://example.com/new-logo.png'
});
// Get current branding
const branding = client.getBranding();
// Set language
client.setLocale('ar', true); // Arabic with RTL
// Get current locale
const locale = client.getLocale();
// Render UI (for preconfigured mode)
await client.render();
// Refresh UI content
await client.refreshUI();Contest Methods
// Get all contests (paginated)
const contests = await client.contests.getAll({ page: 1, per_page: 10 });
// Get trending contests
const trending = await client.contests.getTrending();
// Get premium contests
const premium = await client.contests.getPremium();
// Get recent contests
const recent = await client.contests.getRecent();
// Participate in a contest
await client.contests.participate(contestId);
// Participate with access code (for private contests)
await client.contests.participate(contestId, 'ACCESS_CODE');
// Get contest progress with levels
const progress = await client.contests.getProgress(contestId);
// Get contest history
const history = await client.contests.getHistory();Level Methods
// Complete text level
await client.levels.complete(levelId, { textContent: 'answer' });
// Complete QR level
await client.levels.complete(levelId, { qrCode: 'scanned_data' });
// Complete link level
await client.levels.complete(levelId, { link: 'https://...' });
// Complete image level
await client.levels.completeWithImage(levelId, 'https://image-url.com/photo.jpg');
// OR with base64
await client.levels.completeWithImage(levelId, 'data:image/jpeg;base64,...');
// Get congratulation data after completing a level
const congrats = await client.levels.getCongratulation(levelId, contestId);Quiz Methods
// Start a quiz
const quiz = await client.quiz.start(quizId);
// Returns: attempt, progress, current_question, full_quiz
// Submit an answer
const result = await client.quiz.submitAnswer(attemptId, questionId, optionId);
// Returns: is_correct, progress, can_proceed
// Submit/complete the quiz
const results = await client.quiz.submit(attemptId);
// Returns: score, grade, statisticsUser Management Methods
// Set user identification (before initialization)
client.setUser({
email: '[email protected]',
phone_number: '+923001234567' // Optional
});
// Initialize user session (required for user-specific APIs)
await client.initializeUser();
// Sync user profile data to Luqta
await client.syncUser({
name: 'John Doe',
email: '[email protected]',
phone_number: '+923001234567',
gender: 'male',
country: 'PK'
});
// Sync AND initialize in one call (convenience method)
await client.syncAndInitializeUser({
name: 'John Doe',
email: '[email protected]',
phone_number: '+923001234567'
});
// Check if user is initialized
const isReady = client.isInitialized();Profile Methods
// Get user profile
const profile = await client.profile.get();
// Get user activities
const activities = await client.profile.getActivities();
// Get user progress
const progress = await client.profile.getProgress();
// Submit app feedback
await client.profile.submitFeedback(5, 'Great app!');Reward Methods
// Get rewards list (no user required)
const rewards = await client.rewards.getList();
// Get user earnings (requires user initialization)
const earnings = await client.rewards.getEarnings();
// Redeem a reward
await client.rewards.redeem(rewardId, points);
// Get reward history
const rewardHistory = await client.rewards.getHistory();
// Get prize history
const prizeHistory = await client.rewards.getPrizeHistory();Notification Methods
// Get all notifications
const notifications = await client.notifications.getAll();
// Mark notifications as read
await client.notifications.markAsRead([notificationId1, notificationId2]);
// Update notification settings
await client.notifications.updateSettings({
push_enabled: true,
email_enabled: false
});Level Types
The SDK supports 5 level types:
| Type | Description | Completion Method |
|------|-------------|-------------------|
| text | User enters a text answer | complete(id, { textContent: '...' }) |
| qr | User scans a QR code | complete(id, { qrCode: '...' }) |
| link | User visits a URL | complete(id, { link: '...' }) |
| image | User uploads a photo | completeWithImage(id, 'url') |
| quiz | User answers questions | quiz.start(), quiz.submit() |
Pre-configured UI for Each Type
Text Level:
- Simple input field
- Submit button
QR Level:
- QR icon with animated rings
- "Scan Now" button
- Opens camera for scanning
- Fallback manual input
Link Level:
- Opens URL in new tab
- Auto-completes on visit
Image Level:
- Dashed upload area
- Click to select file
- Image preview before submit
- "Upload photo" button
Quiz Level:
- Question with options
- Progress indicator
- Answer feedback
- Results screen with grade
Error Handling
import { LuqtaClient, LuqtaError } from 'luqta-sdk';
try {
await client.contests.participate(123);
} catch (error) {
if (error instanceof LuqtaError) {
console.error('Error Code:', error.code);
console.error('Message:', error.message);
// Handle specific errors
switch (error.code) {
case 'USER_NOT_INITIALIZED':
await client.initializeUser();
break;
case 'NETWORK_ERROR':
alert('Please check your internet connection');
break;
default:
alert(error.message);
}
}
}Common Error Codes
| Code | Meaning | Solution |
|------|---------|----------|
| MISSING_API_KEY | API key not provided | Add apiKey to config |
| MISSING_APP_ID | App ID not provided | Add appId to config |
| SDK_NOT_INITIALIZED | SDK not initialized | Call initializeSdk() first |
| USER_NOT_INITIALIZED | User session not started | Call initializeUser() first |
| USER_NOT_SYNCED | User needs to be synced first | Call syncUser() or syncAndInitializeUser() |
| MISSING_USER_CONFIG | No user email/phone provided | Set user in config or call setUser() |
| INVALID_EMAIL_FORMAT | Email format invalid | Use valid email |
| INVALID_PHONE_FORMAT | Phone format invalid | Use E.164 format (+123...) |
| NETWORK_ERROR | No internet connection | Check connection |
| TIMEOUT | Request took too long | Try again |
TypeScript Support
The SDK includes full TypeScript definitions:
import {
LuqtaClient,
LuqtaError,
Contest,
Level,
Quiz,
ApiResponse,
PaginatedResponse,
BrandingConfig,
UIConfig,
UIAction,
UserProfile,
UserIdentification
} from 'luqta-sdk';
// Type-safe configuration
const config: PreconfiguredModeConfig = {
mode: 'preconfigured',
apiKey: 'key',
appId: 'app',
containerId: 'container',
user: { email: '[email protected]' }
};
const client = new LuqtaClient(config);
// Type-safe responses
const response: PaginatedResponse<Contest> = await client.contests.getAll();
const contests: Contest[] = response.data.items;FAQ
How do I get API keys?
Contact Luqta support or sign up at luqta.com to get your API key and App ID.
Can I use this without user authentication?
Yes! For public contest listings, you don't need user authentication:
const client = new LuqtaClient({
mode: 'custom',
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID'
// No user needed
});
await client.initializeSdk();
const contests = await client.contests.getAll();How do I change the language?
// Option 1: During initialization
const client = new LuqtaClient({
// ...
locale: 'ar',
rtl: true
});
// Option 2: After initialization
client.setLocale('ar', true);
await client.refreshUI();How do I track user actions?
const client = new LuqtaClient({
// ...
onAction: (action) => {
switch (action.type) {
case 'contest_joined':
analytics.track('Contest Joined', action.data);
break;
case 'level_completed':
analytics.track('Level Completed', action.data);
break;
case 'quiz_completed':
analytics.track('Quiz Completed', action.data);
break;
}
}
});Does it work with React/Vue/Angular?
Yes! The SDK is framework-agnostic. See the Complete Examples section for framework-specific code.
How do I customize the colors?
const client = new LuqtaClient({
// ...
branding: {
primaryColor: '#FF5722', // Orange
secondaryColor: '#FF9800', // Light orange
backgroundColor: '#FAFAFA', // Light gray
textColor: '#212121' // Dark gray
}
});Can I use my own UI?
Yes! Use Custom UI Mode and build your own interface:
const client = new LuqtaClient({
mode: 'custom', // API only, no UI
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID',
user: { email: '[email protected]' }
});
await client.initializeUser();
const contests = await client.contests.getAll();
// Now build your own UI with the dataWhat's the difference between initializeSdk() and initializeUser()?
initializeSdk(): Validates your API key and App ID. No user info needed. Required before fetching contests.initializeUser(): Creates a user session for user-specific actions (participate, complete levels, etc.). Requires email or phone.
// SDK init (app-level) - always do this first
await client.initializeSdk();
// User init (optional) - only if you need user-specific features
await client.initializeUser();What if I get "USER_NOT_SYNCED" error?
This means the user doesn't exist in Luqta yet. Sync them first:
try {
await client.initializeUser();
} catch (error) {
if (error.code === 'USER_NOT_SYNCED') {
await client.syncAndInitializeUser({
name: 'User Name',
email: '[email protected]'
});
}
}Can I configure the UI after creating the client?
Yes! Use the configure() method:
const client = new LuqtaClient({
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID'
});
await client.initializeSdk();
// Configure UI later
client.configure({
containerId: 'luqta-container',
branding: { primaryColor: '#5304fb' }
});
await client.render();Support
- Documentation: https://luqta.com/docs
- GitHub Issues: https://github.com/luqta/luqta-sdk/issues
- Email: [email protected]
License
MIT License - see LICENSE for details.
