This guide explains how to implement user session recovery when users access your application from a different device, typically through email or SMS remarketing campaigns.
Overview
To securely allow users to resume their session on a different device, you’ll need to:
- Generate a Hashed Token, which is generated from the user’s Entry ID, an expiration timestamp, and a Secret Key.
- Send users a secure URL that contains this Hashed Token, as well as the user’s Entry ID and the expiration timestamp.
- When a user opens the URL, use the Hashed Token and other parameters to securely call the Embeddables API from the client, which will return the User Data.
- Use this retrieved User Data to restore the user’s session.
Generating the Hashed Tokens and secure URLs
To generate a Hashed Token and secure URL, you’ll need a Secret Key - contact Embeddables Support to get this Secret Key.
Here’s how to generate the Hashed Token and secure URL:
// Required parameters
const secretKey = process.env.EMBEDDABLES_LOAD_ENTRY_SECRET_KEY
const entryId = "entry_aaabbbcccdddeeefff" // The ID of the user's entry
const expiresAt = "2025-01-01T00:00:00.000Z" // ISO format timestamp
// Generate the hash
const stringToHash = `${secretKey}---${entryId}---${expiresAt}`
const token = sha256(stringToHash, 'utf8', 'hex')
// Construct the final URL
const url = `https://yourwebsite.com/flow?token=${token}&entry_id=${entryId}&expires_at=${expiresAt}`
Client-Side Implementation
Once the user clicks the generated URL, create a Action, triggered on Embeddable Load, with the following code to fetch and restore their session:
// @TODO: Replace these with your own values
const EMBEDDABLE_ID = '<EMBEDDABLE_ID>' // Your Embeddable ID
const TOKEN_URL_PARAM_KEY = 'token' // The URL parameter key for the Hashed Token
const ENTRY_ID_URL_PARAM_KEY = 'entry_id' // The URL parameter key for the user's Entry ID
const EXPIRY_URL_PARAM_KEY = 'expires_at' // The URL parameter key for the expiration timestamp
// All Actions must contain a function called output()
function output(userData, helperFunctions, triggerContext) {
// Grab the token from the URL
const urlParams = (new URL(window.location)).searchParams
const token = urlParams.get(TOKEN_URL_PARAM_KEY)
const entryId = urlParams.get(ENTRY_ID_URL_PARAM_KEY)
const expiresAt = urlParams.get(EXPIRY_URL_PARAM_KEY)
// If we don't have all of token + entry ID + expiry date,
// then stop here (this is a new user or the provided data is incomplete)
if (!token || !entryId || !expiresAt) return
// Fetch the User Data from the Embeddables API
console.log('Retrieving User Data', { token })
fetch(
"https://ierxexdtyashuotcsjyo.supabase.co/functions/v1/load_entry_data",
{
body: JSON.stringify({
flow_id: EMBEDDABLE_ID,
entry_id: entryId,
token,
expires: expiresAt,
}),
headers: {
"Content-Type": "application/json",
},
method: "POST",
}
).then(async (res) => {
const data = await res.json();
console.log('Retrieved User Data: ', { data })
// If the User Data is successfully retrieved,
// set the user data and navigate to the user's current page
if (data && data.entry) {
helperFunctions.setUserData({ ...data.entry });
window.Savvy.goToPage(EMBEDDABLE_ID, data.entry.current_page_key)
}
}).catch((err) => {
console.error('Error Retrieving User Data:', { error })
})
}
Important Notes
- The secret key should always be stored as an encrypted backend environment variable and never exposed in client-side code.
- Each URL should have a reasonable expiration time, e.g. 7 days or 30 days.
- The Hashed Token is unique per user and expiration date.
Troubleshooting
If you’re experiencing issues:
- Verify that the secret key is correctly set in your environment variables
- Ensure the expiration timestamp is in the correct ISO format
- Check that all URL parameters (token, entry_id, expires_at) are properly encoded
- Confirm that the necessary permissions are enabled for your application
Responses are generated using AI and may contain mistakes.