Prebuilt UI
While you can build every experience on your own using our API, Light offers several prebuilt UI solutions that let you easily integrate with the Light platform:
- Embedded flows - Want to keep customers in your experience, but skip building the UI? Embedded flows are a low-code experience where you embed an iframe or webview directly within your product.
- No-code web app - A standalone web app with a complete account management portal ready to go, using your brand. Link your customers to the portal and they'll use their email address to log in.
- No-code flows - These can handle discrete transactional interactions with customers, for example when customers are renewing plans. Customers are sent a Light-hosted flow with your brand.
Experience availability
Use any combination of the API and our prebuilt UI solutions to create your Light integration. Since the prebuilt UI solutions use the same APIs available to you, you can always start with a prebuilt UI and migrate to a direct API integration with custom UI as needed.
| Experience | Embedded flows | No-code web app | No-code flows |
|---|---|---|---|
| Enrollment | X | ||
| Billing | X | X | |
| Documents | X | X | |
| Service | X | ||
| Energy usage | X | ||
| Renewals | X | X |
Brand configuration
The prebuilt UIs have a default look and feel that is designed to be easy to use and integrate. They can be minimally configured with things like logos and company name to match your brand. However, you can completely customize your design by building on top of our APIs directly.
Embedded flows
Light offers optional embedded flows that let you integrate the Light platform into your website or mobile app using a webview or iframe, simplifying your integration and saving development time.
You can launch embedded flows from your application with various scopes to handle parts of the customer journey like Enrollment or Billing. Each embedded flow is built entirely on the same APIs you can use directly.
Scopes
Each embedded flow has a specific scope that determines the flow that will be launched. The following scopes are currently supported, but more scopes will be added in the future. Reach out to us if you have a specific use case that you would like to see supported.
Scopes:
enrollment- Launches the embedded flow with the enrollment experience. Previewupdate-payment-method- Launches the embedded flow for a user to update their payment method. Previewbilling- Launches the embedded flow with the user's invoices. Previewdocuments- Launches the embedded flow with the user's documents. Preview
Tutorial
1. Get an embedded flow link
When you launch an embedded flow, you'll launch it for a specific Account. Use the uuid of the Account as the account_uuid in a POST to /v1/app/accounts/{account_uuid}/flow-login?scope=enrollment:
- Node.js
- Python
- cURL
// Get the embedded flow URL for enrollment
const response = await fetch(
`https://api.light.dev/v1/app/accounts/${accountUuid}/flow-login`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LIGHT_APP_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
scope: "enrollment",
}),
},
);
const flowData = await response.json();
console.log("Flow URL:", flowData.login_link);
import requests
import os
# Get the embedded flow URL for enrollment
response = requests.post(
f'https://api.light.dev/v1/app/accounts/{account_uuid}/flow-login',
headers={
'Authorization': f'Bearer {os.getenv("LIGHT_APP_TOKEN")}',
'Content-Type': 'application/json'
},
json={
'scope': 'enrollment'
}
)
flow_data = response.json()
print(f"Flow URL: {flow_data['login_link']}")
# Get the embedded flow URL for enrollment
curl -X POST "https://api.light.dev/v1/app/accounts/ACCOUNT_UUID/flow-login" \
-H "Authorization: Bearer $LIGHT_APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scope": "enrollment"
}'
{
"login_link": "https://flow.light.dev/login?token=6277d9fb7b76832d1fc7545d4ed649d7",
"scope": "enrollment",
"expires_at": "2025-09-30T14:30:00.753Z"
}
The login_link returned will be a pre-authenticated flow link that can be used to launch an iframe or webview. The expires_at indicates when the pre-authenticated token included in the login_link will expire.
2. Surface the embedded flow at the right moment
The embedded flow is usually displayed inside an iframe or webview after a user clicks a button or navigates to another page.
For end users to successfully navigate an embedded flow, no other UI elements should visually appear on top of the iframe or webview. Ensure other UI elements, such as nav bars, have a lower z-index and are not absolute-positioned on top.
- HTML
- React
<iframe
src="https://flow.light.dev/login?token=6277d9fb7b76832d1fc7545d4ed649d7"
width="100%"
height="100%"
style="position: fixed; top: 0; left: 0; z-index: 99999;"
title="Light Flow"
></iframe>
import React from "react";
interface FlowIframeProps {
url: string;
}
const FlowIframe: React.FC<FlowIframeProps> = ({ url }) => {
return (
<iframe
src={url}
width="100%"
height="100%"
style={{
position: "fixed",
top: 0,
left: 0,
zIndex: 99999,
}}
title="Light Flow"
/>
);
};
export default FlowIframe;
3. Close the enrollment flow
You'll need to close the embedded flow once a user chooses to exit the flow. Close the embedded flow by listening for the light-flow-close event emitted by the embedded flow.
- HTML
- React
<!doctype html>
<html>
<head>
<title>Light Enrollment Flow</title>
<style>
.flow-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
}
.flow-iframe {
width: 100%;
height: 100%;
border: none;
}
</style>
</head>
<body>
<div id="flow-container" class="flow-container" style="display: none;">
<iframe id="flow-iframe" class="flow-iframe" title="Light Flow"></iframe>
</div>
<script>
function showFlow(url) {
const container = document.getElementById("flow-container");
const iframe = document.getElementById("flow-iframe");
iframe.src = url;
container.style.display = "block";
// Listen for the close event
window.addEventListener("message", handleMessage);
}
function hideFlow() {
const container = document.getElementById("flow-container");
container.style.display = "none";
// Remove the event listener
window.removeEventListener("message", handleMessage);
}
function handleMessage(event) {
const eventType = event.data?.type;
if (!eventType) {
return;
}
if (eventType === "light-flow-close") {
hideFlow();
}
}
</script>
</body>
</html>
import React, { useEffect } from "react";
interface FlowIframeProps {
url: string;
onClose: () => void;
}
const FlowIframe: React.FC<FlowIframeProps> = ({ url, onClose }) => {
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
const eventType = event.data?.type;
if (!eventType) {
return;
}
if (eventType === "light-flow-close") {
onClose();
}
};
window.addEventListener("message", handleMessage);
return () => {
window.removeEventListener("message", handleMessage);
};
}, [onClose]);
return (
<iframe
src={url}
width="100%"
height="100%"
style={{
position: "fixed",
top: 0,
left: 0,
zIndex: 99999,
}}
title="Light Flow"
/>
);
};
export default FlowIframe;
No-code web app
On a deadline? We also have a prebuilt account portal app that you can white-label with no-code to get started, which handles everything your customers need after enrollment. Reach out for us to get started.
No-code flows
These are prebuilt UI flows hosted by Light to handle discrete interactions with customers. These can be used for out-of-band experiences like renewals to save you time of building for all paths at launch. They are typically launched via a pre-authenticated email link, providing a quick and branded interaction for the customer.
Scopes
The following scopes are currently supported, but more scopes will be added in the future. Reach out to us if you have a specific use case that you would like to see supported.
Scopes:
renewal- Launches the no-code flow with the renewal experience.