Javascript client library for Resync Content Management System
npm install resync-javascriptA powerful JavaScript library for dynamic content management, remote configuration, and in-app campaign. Resync allows you to manage embed dynamic banners, ctas, forms, text, run campaigns into your mobile app. Deliver dynamic content without app updates. Works seamlessly across JavaScript, React Native, and Expo applications.
- ๐ Remote Configuration - Manage app configs remotely without code deployments
- ๐งช In-app Campaigns - Run campaigns with audiences, automatic variant assignment and tracking
- ๐จ Dynamic Content Management - Fetch and render content blocks defined in your Resync dashboard
- ๐ Event Logging - Track custom events and user interactions
- ๐พ Smart Caching - Automatic environment-based caching (6h production, 0ms development)
- ๐ Real-time Updates - Subscribe to configuration changes with callback support
- ๐ฑ Cross-Platform - Works with vanilla JavaScript, React Native, and Expo
- ๐ง TypeScript Support - Full TypeScript definitions included
- ๐ฏ User Targeting - Set user attributes for personalized experiences and audience creation.
``sh`
npm install resync-javascriptor
yarn add resync-javascript
`javascript
import Resync from 'resync-javascript';
// Initialize Resync with your API credentials
await Resync.init({
key: 'your-api-key',
appId: 7,
callback: async (config) => {
console.log('Resync initialized with config:', config);
},
storage: localStorage, // or AsyncStorage for React Native
environment: 'production',
});
`
`javascript
// Get a specific config value
const featureEnabled = Resync.getConfig('FEATURE_FLAG');
const apiEndpoint = Resync.getConfig('API_ENDPOINT');
console.log('Feature enabled:', featureEnabled);
`
`javascript
// Get variant for an Campaign experiment
const variant = await Resync.getVariant('homepage_experiment');
if (variant === 'variant_a') {
// Show variant A
} else {
// Show variant B
}
`
`javascript`
// Log custom events
Resync.logEvent({
eventId: 'evt_button_clicked',
metadata: {
buttonName: 'signup',
screen: 'homepage',
},
});
`javascript
// Fetch all content blocks
const contentBlocks = Resync.getContent();
// Find a specific content view by name
const welcomeCard = contentBlocks.find(
(view) => view.name === 'HomeWelcomeCard'
);
console.log('Welcome card content:', welcomeCard);
`
Initialize the Resync SDK. Must be called before using any other methods.
#### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| key | string | โ
| Your Resync API key |appId
| | number | โ
| Your application ID |callback
| | () => void | โ | Callback function invoked when config is loaded |storage
| | Storage | โ
| Storage object for caching (localStorage, AsyncStorage, etc.) |environment
| | sandbox | production | โ
| Environment for your project |
#### Returns
Promise - Returns the Resync instance
#### Example
`javascript`
await Resync.init({
key: 'rsk_live_abc123',
appId: 7,
callback: () => {
console.log('Config loaded:');
},
storage: localStorage,
environment: 'sandbox'
});
---
Get a configuration value by key.
#### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| key | string | โ
| Configuration key to retrieve |
#### Returns
any - The configuration value
#### Example
`javascript
const apiUrl = Resync.getConfig('API_BASE_URL');
const maxRetries = Resync.getConfig('MAX_RETRIES');
const features = Resync.getConfig('ENABLED_FEATURES');
console.log('API URL:', apiUrl);
console.log('Max retries:', maxRetries);
`
---
Get the assigned variant for a Campaign.
#### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| campaignName | string | โ
| Name of the campaign |
#### Returns
Promise - Returns the variant content view ID or null
#### Example
`javascript
const variant = await Resync.getVariant('checkout_flow_test');
if (variant === 123) {
// Show variant A (content view ID 123)
renderCheckoutVariantA();
} else if (variant === 124) {
// Show variant B (content view ID 124)
renderCheckoutVariantB();
}
`
---
Get all content blocks from the current configuration.
#### Returns
ContentView[] - Array of content blocks
#### Example
`javascript
const contentBlocks = Resync.getContent();
// Find specific content view
const bannerContent = contentBlocks.find(
(view) => view.name === 'PromoAnnouncement'
);
// Iterate through all published content
contentBlocks
.filter((view) => view.status === 'published')
.forEach((view) => {
console.log(Content view: ${view.name});`
});
---
Set the user ID for tracking and personalized variant assignment.
#### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| userId | string \| number | โ
| Unique user identifier |metadata
| | object | โ | User metadata (email, name, phone, language) |
#### Returns
Promise - Returns true if successful
#### Example
`javascript
// Simple user ID
await Resync.loginUser('user_12345');
// With metadata
await Resync.loginUser('user_12345', {
email: 'user@example.com',
name: 'John Doe',
phone: '+1234567890',
language: 'en',
});
`
---
Set user attributes for targeting and personalization.
#### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| attributes | object | โ
| User attributes object |attributes.email
| | string | โ | User email |attributes.name
| | string | โ | User name |attributes.phone
| | string | โ | User phone |attributes.language
| | string | โ | User language |attributes.attributes
| | object | โ | Additional custom attributes |
#### Returns
Promise - Returns true if successful
#### Example
`javascript`
await Resync.setUserAttributes({
email: 'user@example.com',
name: 'Jane Smith',
phone: '+1234567890',
language: 'en',
attributes: {
subscriptionTier: 'premium',
country: 'US',
signupDate: '2025-01-15',
},
});
---
Set a client identifier for tracking purposes.
#### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| client | string | โ
| Client identifier (e.g., 'web', 'mobile', 'ios', 'android') |
#### Example
`javascript`
Resync.setClient('web');
// or
Resync.setClient('mobile-ios');
---
Log a custom event for analytics and tracking.
#### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| event | object | โ
| Event object |event.eventId
| | string | โ
| Event identifier |event.logId
| | string | โ | External log ID for correlation |event.metadata
| | object | โ | Additional event metadata |
#### Example
`javascript
// Simple event
Resync.logEvent({
eventId: 'evt_user_signup',
});
// Event with metadata
Resync.logEvent({
eventId: 'evt_purchase_completed',
logId: 'order_789',
metadata: {
amount: 99.99,
currency: 'USD',
productId: 'prod_123',
quantity: 2,
},
});
`
---
Submit form data to the Resync backend.
#### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| formData | object | โ
| Form submission object |formData.contentViewId
| | number | โ
| Content view ID of the form |formData.data
| | object | โ
| Form field data |
#### Returns
Promise - Returns true if successful, Error otherwise
#### Example
`javascript
try {
const success = await Resync.submitForm({
contentViewId: 456,
data: {
name: 'John Doe',
email: 'john@example.com',
message: 'Hello!',
},
});
if (success) {
console.log('Form submitted successfully');
}
} catch (error) {
console.error('Form submission failed:', error);
}
`
---
Subscribe to configuration updates. The callback will be invoked whenever the configuration changes.
#### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| callback | (config: AppConfig) => void | โ
| Callback function |
#### Example
`javascript
function handleConfigUpdate(config) {
console.log('Config updated:', config);
// Update UI or app state
}
Resync.subscribe(handleConfigUpdate);
`
---
Unsubscribe from configuration updates.
#### Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| callback | (config: AppConfig) => void | โ
| Previously subscribed callback function |
#### Example
`javascript`
Resync.unsubscribe(handleConfigUpdate);
Subscribe to configuration changes to update your app dynamically:
`javascript
await Resync.init({
key: 'your-api-key',
appId: 7,
storage: localStorage,
callback: () => {
console.log('Initial config loaded:');
},
environment: 'sandbox'
});
// Subscribe to future updates
Resync.subscribe(() => {
console.log('Config updated!');
// Update your app's state or UI
updateAppSettings();
});
`
Combine user attributes for targeted campaigns:
`javascript
// Set user attributes
await Resync.loginUser('user_123', {
email: 'user@example.com',
name: 'Alice',
});
await Resync.setUserAttributes({
attributes: {
userTier: 'premium',
region: 'north-america',
},
});
// Get variant (assignment may be based on attributes)
const variant = await Resync.getVariant('premium_feature_test');
if (variant) {
// Show experiment variant
} else {
// Show control
}
`
Use remote config for feature flagging:
`javascript
// Check if a feature is enabled
const newUIEnabled = Resync.getConfig('ENABLE_NEW_UI');
const darkModeAvailable = Resync.getConfig('DARK_MODE_AVAILABLE');
if (newUIEnabled) {
renderNewUI();
} else {
renderLegacyUI();
}
// Get configuration objects
const apiSettings = Resync.getConfig('API_SETTINGS');
console.log('API timeout:', apiSettings?.timeout);
console.log('Max retries:', apiSettings?.maxRetries);
`
Build a comprehensive event tracking system:
`javascript
// Track user journey
Resync.logEvent({
eventId: 'evt_app_opened',
metadata: { timestamp: Date.now() },
});
// Track interactions
document.getElementById('cta-button').addEventListener('click', () => {
Resync.logEvent({
eventId: 'evt_cta_clicked',
metadata: {
buttonId: 'cta-button',
page: 'homepage',
},
});
});
// Track conversions
async function completePurchase(orderId, amount) {
await processPayment();
Resync.logEvent({
eventId: 'evt_purchase_completed',
logId: orderId,
metadata: {
amount,
currency: 'USD',
timestamp: Date.now(),
},
});
}
`
Use different storage adapters based on your platform:
#### Browser (Web)
`javascript`
await Resync.init({
key: 'your-api-key',
appId: 7,
storage: localStorage, // or sessionStorage
environment: 'sandbox'
});
#### React Native
`javascript
import AsyncStorage from '@react-native-async-storage/async-storage';
await Resync.init({
key: 'your-api-key',
appId: 7,
storage: AsyncStorage,
environment: 'sandbox'
});
`
#### Custom Storage Adapter
`javascript
// Implement your own storage adapter
const customStorage = {
async getItem(key) {
// Your implementation
},
async setItem(key, value) {
// Your implementation
},
async removeItem(key) {
// Your implementation
},
async clear() {
// Your implementation
},
};
await Resync.init({
key: 'your-api-key',
appId: 7,
storage: customStorage,
environment: 'sandbox'
});
`
The library includes comprehensive TypeScript definitions:
`typescript
import Resync, {
InitOptions,
AppConfig,
ContentView,
Experiment,
ExperimentVariant,
AppEvent,
Storage,
} from 'resync';
// Type-safe initialization
const options: InitOptions = {
key: 'your-api-key',
appId: 7,
callback: () => {
console.log('Resync loaded');
},
storage: localStorage,
};
await Resync.init(options);
// Type-safe event logging
const event: AppEvent = {
eventId: 'evt_user_action',
metadata: {
action: 'click',
target: 'button',
},
};
Resync.logEvent(event);
`
- โ
JavaScript (ES6+) - Modern JavaScript environments
- โ
React Native - iOS and Android apps
- โ
Expo - Managed and bare workflows
- โ
Node.js - Server-side JavaScript (with compatible storage)
- โ
Web Browsers - Chrome, Firefox, Safari, Edge
Initialize Resync as early as possible in your application lifecycle:
`javascript
// App entry point
import Resync from 'resync';
async function initializeApp() {
await Resync.init({
key: process.env.RESYNC_API_KEY,
appId: parseInt(process.env.RESYNC_APP_ID),
storage: localStorage,
environment: 'sandbox'
});
// Continue app initialization
startApp();
}
initializeApp();
`
Note: Cache TTL is automatically configured based on your environment:
- Development: No caching (always fetches fresh data for fast iteration)
- Production: 6 hours cache (optimal performance)
Always handle potential errors:
`javascript`
try {
await Resync.init({
key: 'your-api-key',
appId: 7,
storage: localStorage,
environment: 'sandbox'
});
} catch (error) {
console.error('Failed to initialize Resync:', error);
// Fallback to default configuration
}
Store API credentials securely:
`javascript`
await Resync.init({
key: process.env.RESYNC_API_KEY,
appId: parseInt(process.env.RESYNC_APP_ID),
storage: localStorage,
environment: 'sandbox'
});
The SDK automatically manages caching based on your environment:
`javascript
await Resync.init({
key: 'your-api-key',
appId: 7,
storage: localStorage,
environment: 'sandbox'
});
// Cache TTL is set automatically:
// - Development: 0ms (no caching, always fresh)
// - Production: 6 hours (21600000ms)
`
Unsubscribe from updates when components unmount:
`javascript
function MyComponent() {
useEffect(() => {
const handleUpdate = (config) => {
console.log('Config updated:', config);
};
Resync.subscribe(handleUpdate);
return () => {
Resync.unsubscribe(handleUpdate);
};
}, []);
}
`
Problem: "API key is required" error
Solution: Ensure you're passing the API key during initialization:
`javascript`
await Resync.init({
key: 'rsk_live_your_api_key', // Make sure this is set
appId: 7,
storage: localStorage,
environment: 'sandbox'
});
Problem: "Storage is required" error
Solution: Provide a valid storage object:
`javascript
// Web
await Resync.init({
key: 'your-api-key',
appId: 7,
storage: localStorage, // Add storage
environment: 'sandbox'
});
// React Native
import AsyncStorage from '@react-native-async-storage/async-storage';
await Resync.init({
key: 'your-api-key',
appId: 7,
storage: AsyncStorage, // Add storage
environment: 'sandbox'
});
``
Problem: Configuration values aren't updating in production
Solution: The cache TTL is automatically set based on environment:
- Production: 6 hours cache
- Development: No cache (always fresh)
Check out the example for a complete working example.
MIT
---
Built with โค๏ธ for developers who ship fast