Data Portability
React Achievements exposes import and export helpers for backups, account migration, support tooling, and cross-device sync.
Export Data
exportData() returns a JSON string representing the active achievement state.
import { useAchievements } from 'react-achievements';
function BackupButton() {
const { exportData } = useAchievements();
return (
<button
onClick={() => {
const json = exportData();
console.log(json);
}}
>
Export achievements
</button>
);
}
Download the export as a file:
function DownloadBackup() {
const { exportData } = useAchievements();
const handleDownload = () => {
const json = exportData();
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `achievements-backup-${Date.now()}.json`;
link.click();
URL.revokeObjectURL(url);
};
return <button onClick={handleDownload}>Download backup</button>;
}
Import Data
importData(json, options) validates and imports a previous export.
function RestoreButton({ backupJson }: { backupJson: string }) {
const { importData } = useAchievements();
const handleRestore = () => {
const result = importData(backupJson, { merge: true });
if (!result.success) {
console.error(result.errors);
return;
}
console.log('Achievement data restored.');
};
return <button onClick={handleRestore}>Restore backup</button>;
}
Import Options
type ImportOptions = {
merge?: boolean;
overwrite?: boolean;
validateConfig?: boolean;
expectedConfigHash?: string;
};
Common modes:
importData(json)imports the export using the engine defaults.importData(json, { merge: true })combines imported data with current progress.importData(json, { overwrite: true })allows imported values to replace current values.importData(json, { validateConfig: true, expectedConfigHash })validates that the backup matches the expected achievement configuration.
Import Result
type ImportResult = {
success: boolean;
errors?: string[];
warnings?: string[];
mergedMetrics?: AchievementMetrics;
mergedUnlocked?: string[];
};
Always check success before showing a success message.
const result = importData(json, { merge: true });
if (result.success) {
toast.success('Achievements restored.');
} else {
toast.error(result.errors?.join(', ') || 'Import failed.');
}
File Upload
function UploadBackup() {
const { importData } = useAchievements();
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
const json = e.target?.result as string;
const result = importData(json, { merge: true });
if (!result.success) {
alert(result.errors?.join(', ') || 'Restore failed.');
}
};
reader.readAsText(file);
};
return <input type="file" accept="application/json,.json" onChange={handleFileChange} />;
}
Cloud Sync Pattern
Use exportData() to send a snapshot to your backend, and importData() to restore it.
function SyncControls({ userId }: { userId: string }) {
const { exportData } = useAchievements();
const syncToServer = async () => {
await fetch(`/api/users/${userId}/achievements`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: exportData(),
});
};
return <button onClick={syncToServer}>Sync achievements</button>;
}
For live multi-device sync, prefer a custom storage adapter or RestApiStorage; import/export is best for snapshots, backups, and support workflows.