IO Script Examples
Three common patterns ready to copy into your IO Script editor.
Example 1: Set a custom field on the identity
Where to place: After Auth → true, before the Success Final node.
What it does: Reads the utm_source query parameter from the initiating URL and writes it to a custom field signupSource on the user's profile.
// Sets a custom field "signupSource" on the user's profile
exports.execute = async (lrObject, hook) => {
const uid = await lrObject.getUid();
if (!uid) {
hook.setError(500, "uid_unavailable", "Could not resolve user identity.");
return;
}
const source = hook.getQueryParam("utm_source") || "direct";
await lrObject.updateProfile(uid, { CustomFields: { signupSource: source } });
};
Example 2: Check an external blocklist before registration
Where to place: After the registration Web Page node, before Create User.
What it does: Calls an external blocklist API with the submitted email. Calls hook.setError() if the email is blocked, routing to the false output and preventing account creation.
// Checks an external blocklist before allowing registration
exports.execute = async (lrObject, hook) => {
const email = hook.getFormField("email");
if (!email) {
hook.setError(400, "missing_email", "Email field is required.");
return;
}
const res = await fetch(
`https://api.example.com/blocklist?email=${encodeURIComponent(email)}`
);
const { blocked } = await res.json();
if (blocked) {
hook.setError(400, "email_blocklisted", "This email address is not permitted.");
return;
}
};
If api.example.com is slow, wrap the fetch in a Promise.race with a 4-second timeout to stay within the 5-second script limit.
Example 3: Inspect access token and set session flags
Where to place: After Auth → true, before any downstream MFA or enrichment step.
What it does: Decodes the JWT access token (informational only: no signature verification) and stores the expiry time and issuer in session state for downstream nodes.
// Reads the access token from session and stores expiry info
exports.execute = async (lrObject, hook) => {
const token = lrObject.getAccessToken();
if (!token) {
hook.setError(401, "token_unavailable", "No access token found in session.");
return;
}
// Decode JWT payload: informational only, no signature verification
const [, payload] = token.split(".");
const decoded = JSON.parse(Buffer.from(payload, "base64").toString());
hook.sharedState.set("tokenExp", String(decoded.exp));
hook.sharedState.set("tokenIssuer", decoded.iss);
};
This pattern is useful for logging or routing decisions. Never use the decoded payload as a trust boundary: always verify tokens server-side using your API key secret when making security decisions.
- lrObject API: all identity methods
- Hook API: all session read/write methods