Skip to main content

Resync JavaScript

A 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.

Featuresโ€‹

  • ๐Ÿš€ 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 views 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.

Installationโ€‹

npm install resync-javascript
# or
yarn add resync-javascript

Quick Startโ€‹

1. Initialize Resyncโ€‹

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',
});

2. Get Remote Configurationโ€‹

// Get a specific config value
const featureEnabled = Resync.getConfig('FEATURE_FLAG');
const apiEndpoint = Resync.getConfig('API_ENDPOINT');

console.log('Feature enabled:', featureEnabled);

3. Campaignโ€‹

// Get variant for an Campaign experiment
const variant = await Resync.getVariant('homepage_experiment');

if (variant === 'variant_a') {
// Show variant A
} else {
// Show variant B
}

4. Event Loggingโ€‹

// Log custom events
Resync.logEvent({
eventId: 'evt_button_clicked',
metadata: {
buttonName: 'signup',
screen: 'homepage',
},
});

5. Get Content Blocksโ€‹

// Fetch all content views
const contentViews = Resync.getContent();

// Find a specific content view by name
const welcomeCard = contentViews.find(
(view) => view.name === 'HomeWelcomeCard'
);

console.log('Welcome card content:', welcomeCard);

API Referenceโ€‹

Resync.init(options)โ€‹

Initialize the Resync SDK. Must be called before using any other methods.

Parametersโ€‹

ParameterTypeRequiredDescription
keystringโœ…Your Resync API key
appIdnumberโœ…Your application ID
callback() => voidโŒCallback function invoked when config is loaded
storageStorageโœ…Storage object for caching (localStorage, AsyncStorage, etc.)
environmentsandboxproductionโœ…

Returnsโ€‹

Promise<void> - Returns the Resync instance

Exampleโ€‹

await Resync.init({
key: 'rsk_live_abc123',
appId: 7,
callback: () => {
console.log('Config loaded:');
},
storage: localStorage,
environment: 'sandbox'
});

Resync.getConfig(key)โ€‹

Get a configuration value by key.

Parametersโ€‹

ParameterTypeRequiredDescription
keystringโœ…Configuration key to retrieve

Returnsโ€‹

any - The configuration value

Exampleโ€‹

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);

Resync.getVariant(campaignName)โ€‹

Get the assigned variant for a Campaign.

Parametersโ€‹

ParameterTypeRequiredDescription
campaignNamestringโœ…Name of the campaign

Returnsโ€‹

Promise<number | null> - Returns the variant content view ID or null

Exampleโ€‹

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();
}

Resync.getContent()โ€‹

Get all content views from the current configuration.

Returnsโ€‹

ContentView[] - Array of content views

Exampleโ€‹

const contentViews = Resync.getContent();

// Find specific content view
const bannerContent = contentViews.find(
(view) => view.name === 'PromoAnnouncement'
);

// Iterate through all published content
contentViews
.filter((view) => view.status === 'published')
.forEach((view) => {
console.log(`Content view: ${view.name}`);
});

Resync.loginUser(userId, metadata)โ€‹

Set the user ID for tracking and personalized variant assignment.

Parametersโ€‹

ParameterTypeRequiredDescription
userIdstring | numberโœ…Unique user identifier
metadataobjectโŒUser metadata (email, name, phone, language)

Returnsโ€‹

Promise<boolean> - Returns true if successful

Exampleโ€‹

// 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',
});

Resync.setUserAttributes(attributes)โ€‹

Set user attributes for targeting and personalization.

Parametersโ€‹

ParameterTypeRequiredDescription
attributesobjectโœ…User attributes object
attributes.emailstringโŒUser email
attributes.namestringโŒUser name
attributes.phonestringโŒUser phone
attributes.languagestringโŒUser language
attributes.attributesobjectโŒAdditional custom attributes

Returnsโ€‹

Promise<boolean> - Returns true if successful

Exampleโ€‹

await Resync.setUserAttributes({
email: 'user@example.com',
name: 'Jane Smith',
phone: '+1234567890',
language: 'en',
attributes: {
subscriptionTier: 'premium',
country: 'US',
signupDate: '2025-01-15',
},
});

Resync.setClient(client)โ€‹

Set a client identifier for tracking purposes.

Parametersโ€‹

ParameterTypeRequiredDescription
clientstringโœ…Client identifier (e.g., 'web', 'mobile', 'ios', 'android')

Exampleโ€‹

Resync.setClient('web');
// or
Resync.setClient('mobile-ios');

Resync.logEvent(event)โ€‹

Log a custom event for analytics and tracking.

Parametersโ€‹

ParameterTypeRequiredDescription
eventobjectโœ…Event object
event.eventIdstringโœ…Event identifier
event.logIdstringโŒExternal log ID for correlation
event.metadataobjectโŒAdditional event metadata

Exampleโ€‹

// 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,
},
});

Resync.submitForm(formData)โ€‹

Submit form data to the Resync backend.

Parametersโ€‹

ParameterTypeRequiredDescription
formDataobjectโœ…Form submission object
formData.contentViewIdnumberโœ…Content view ID of the form
formData.dataobjectโœ…Form field data

Returnsโ€‹

Promise<boolean | Error> - Returns true if successful, Error otherwise

Exampleโ€‹

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);
}

Resync.subscribe(callback)โ€‹

Subscribe to configuration updates. The callback will be invoked whenever the configuration changes.

Parametersโ€‹

ParameterTypeRequiredDescription
callback(config: AppConfig) => voidโœ…Callback function

Exampleโ€‹

function handleConfigUpdate(config) {
console.log('Config updated:', config);
// Update UI or app state
}

Resync.subscribe(handleConfigUpdate);

Resync.unsubscribe(callback)โ€‹

Unsubscribe from configuration updates.

Parametersโ€‹

ParameterTypeRequiredDescription
callback(config: AppConfig) => voidโœ…Previously subscribed callback function

Exampleโ€‹

Resync.unsubscribe(handleConfigUpdate);

Advanced Usageโ€‹

Real-time Configuration Updatesโ€‹

Subscribe to configuration changes to update your app dynamically:

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();
});

User Segmentation with attributesโ€‹

Combine user attributes for targeted campaigns:

// 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
}

Dynamic Feature Flagsโ€‹

Use remote config for feature flagging:

// 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);

Event Tracking Pipelineโ€‹

Build a comprehensive event tracking system:

// 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(),
},
});
}

Storage Adaptersโ€‹

Use different storage adapters based on your platform:

Browser (Web)โ€‹

await Resync.init({
key: 'your-api-key',
appId: 7,
storage: localStorage, // or sessionStorage
environment: 'sandbox'
});

React Nativeโ€‹

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โ€‹

// 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'
});

TypeScript Supportโ€‹

The library includes comprehensive TypeScript definitions:

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);

Platform Supportโ€‹

  • โœ… 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

Best Practicesโ€‹

1. Initialize Earlyโ€‹

Initialize Resync as early as possible in your application lifecycle:

// 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)

2. Handle Errors Gracefullyโ€‹

Always handle potential errors:

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
}

3. Use Environment Variablesโ€‹

Store API credentials securely:

await Resync.init({
key: process.env.RESYNC_API_KEY,
appId: parseInt(process.env.RESYNC_APP_ID),
storage: localStorage,
environment: 'sandbox'
});

4. Automatic Cache Managementโ€‹

The SDK automatically manages caching based on your environment:

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)

5. Clean Up Subscriptionsโ€‹

Unsubscribe from updates when components unmount:

function MyComponent() {
useEffect(() => {
const handleUpdate = (config) => {
console.log('Config updated:', config);
};

Resync.subscribe(handleUpdate);

return () => {
Resync.unsubscribe(handleUpdate);
};
}, []);
}

Troubleshootingโ€‹

API Key Issuesโ€‹

Problem: "API key is required" error

Solution: Ensure you're passing the API key during initialization:

await Resync.init({
key: 'rsk_live_your_api_key', // Make sure this is set
appId: 7,
storage: localStorage,
environment: 'sandbox'
});

Storage Issuesโ€‹

Problem: "Storage is required" error

Solution: Provide a valid storage object:

// 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'
});

Configuration Not Updatingโ€‹

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)

Licenseโ€‹

MIT


Built with โค๏ธ for developers who ship fast