Initialization
- Next.JS(TypeScript)
- Vanilla.js
- Create
.env
file - Store your credentials from Authentification in
.env
file
NEXT_PUBLIC_CLIENT_ID=YOUR_CLIENT_ID
- Import SDK
import VeryfiLens from 'veryfi-lens-wasm'
const VeryfiLens = require('veryfi-lens-wasm').default
- Add a function to validate partner and receive session token (it is necessary to initialize Lens)
const validatePartner = async (clientId: string): Promise<any> => {
const validateUrl = 'https://lens.veryfi.com/rest/validate_partner';
const requestOptions = {
method: 'POST',
headers: {
'CLIENT-ID': clientId,
},
};
return fetch(validateUrl, requestOptions)
.then((response) => response.json())
.then((data) => {
return data.session;
})
.catch((error) => {
return error;
});
};
- Initialize lens
useEffect(() => {
const startWasm = () => {
if (typeof window !== "undefined") {
veryfiLens.initCC(sessionToken, CLIENT_ID);
}
};
startWasm();
}, []);
- Get card data
useEffect(() => {
let isMounted = true;
if (veryfiLens) {
const intervalId = setInterval(async () => {
if (!isMounted) return;
try {
const data = await veryfiLens.getCardData();
setPhase(veryfiLens.getCardPhase());
if (data) {
setCardData(data);
if (
data.cvv !== "" ||
(data.status === "AutoCaptureResultDone" &&
phase === "ScanningBack")
) {
setCardData(data);
setHasData(true);
clearInterval(intervalId);
console.log("All data received, interval cleared.");
setIsEditing(true);
veryfiLens.stopCameraWasm();
return;
}
}
} catch (error) {
console.error("An error occurred while fetching data:", error);
}
}, 1000);
return () => {
isMounted = false;
clearInterval(intervalId);
};
}
}, []);
Take a look at the complete Next.js component
import React, { useEffect, Dispatch, SetStateAction, useState } from "react";
import GoHomeButton from "./GoHomeButton";
export interface CardComponentProps {
sessionToken: string;
setImage: Dispatch<SetStateAction<string>>;
setIsEditing: Dispatch<SetStateAction<boolean>>;
deviceData: any;
setDeviceData: React.Dispatch<React.SetStateAction<any>>;
setIsCard: React.Dispatch<React.SetStateAction<any>>;
cardData: {
status: string;
name: string;
number: string;
cvv: string;
date: string;
};
setCardData: React.Dispatch<
React.SetStateAction<{
status: string;
name: string;
number: string;
cvv: string;
date: string;
}>
>;
veryfiLens: any;
}
const CardComponent = ({
sessionToken,
deviceData,
setDeviceData,
setIsEditing,
cardData,
setIsCard,
setCardData,
veryfiLens,
}: CardComponentProps) => {
const [hasData, setHasData] = useState(false);
const [phase, setPhase] = useState("");
const CLIENT_ID = process.env.NEXT_PUBLIC_CLIENT_ID;
useEffect(() => {
const startWasm = () => {
if (typeof window !== "undefined") {
veryfiLens.initCC(sessionToken, CLIENT_ID);
}
};
startWasm();
}, []);
useEffect(() => {
let isMounted = true;
if (veryfiLens) {
const intervalId = setInterval(async () => {
if (!isMounted) return;
try {
const data = await veryfiLens.getCardData();
setPhase(veryfiLens.getCardPhase());
if (data) {
setCardData(data);
if (
data.cvv !== "" ||
(data.status === "AutoCaptureResultDone" &&
phase === "ScanningBack")
) {
setCardData(data);
setHasData(true);
clearInterval(intervalId);
console.log("All data received, interval cleared.");
setIsEditing(true);
veryfiLens.stopCameraWasm();
return;
}
}
} catch (error) {
console.error("An error occurred while fetching data:", error);
}
}, 1000);
return () => {
isMounted = false;
clearInterval(intervalId);
};
}
}, []);
const handleSubmit = () => {
setIsEditing(true);
veryfiLens.stopCameraWasm();
};
return (
<div className="flex relative h-full w-full">
<GoHomeButton id="go_home" setter={setIsCard} />
<div
className="flex absolute justify-center w-full h-full overflow-hidden"
id="veryfi-container"
></div>
<div className="text-black bg-white z-[100]"></div>
{
<div className="absolute flex w-full flex-col justify-center items-center z-[900]">
<div className="w-full h-full flex flex-col justify-center items-center pointer-events-none z-[60] mt-[40vh]">
<div className="border-solid loading-border-relative border-[8px] w-[400px] h-[250px] border-white rounded-xl p-4 bg-black bg-opacity-30 relative overflow-hidden">
{cardData && (
<div>
<p className="text-white text-xl m-10 ml-14">
{cardData.number}
</p>
<p className="text-white text-lg text-left">
{cardData.date}
</p>
<p className="text-white text-lg text-left">
{cardData.name}
</p>
{hasData && cardData.cvv && (
<p className="text-white text-lg text-right">
{cardData.cvv}
</p>
)}
</div>
)}
</div>
</div>
{cardData && (
<div>
{phase === "FlipCard" && (
<p className=" z-[60] text-white font-bold mt-5 text-[25px]">
Please flip your card
</p>
)}
</div>
)}
<button
className="z-[60] h-[50px] w-[200px] mt-5 bg-[#00FA6C] text-white font-bold"
onClick={() => handleSubmit()}
>
Submit
</button>
</div>
}
</div>
);
};
export default CardComponent;
Set your client id from Authentification
Add a function to validate partner and receive session token (it is necessary to initialize Lens)
async function validatePartner(clientId) {
const validateUrl = "https://lens.veryfi.com/rest/validate_partner";
try {
const requestOptions = {
method: "POST",
headers: { "CLIENT-ID": clientId },
};
const response = await fetch(validateUrl, requestOptions);
const data = await response.json();
return data.session;
} catch (error) {
console.error("Error validating partner:", error);
return null;
}
}
- import SDK
import VeryfiLens from "./lens-sdk-wasm/veryfi-lens.js";
- Add the following HTML to your page
<div id="veryfi-container" class="v-container">
<div id="card-wrapper" class="card-wrapper"><div id="card-wrapper" class="card-wrapper">
<div id="card-container" class="card-container">
<div id="card" class="card">
<div id="dynamicContent"></div>
</div>
</div>
</div>
</div>
<div id="flip-card-message" class="flip-card-message">
Please flip your card
</div>
- Add a function to poll card data
function pollCardData() {
let intervalId = setInterval(async () => {
try {
const data = await VeryfiLens.getCardData();
const phase = VeryfiLens.getCardPhase();
if (data) {
renderCardData(data);
if (phase === "FlipCard") {
displayFlipCardMessage();
} else {
hideFlipCardMessage();
}
if (
data.cvv !== "" ||
(data.status === "AutoCaptureResultDone" && phase === "ScanningBack")
) {
renderCardData(data);
clearInterval(intervalId);
console.log("All data received, interval cleared.");
VeryfiLens.stopCameraWasm();
return;
}
}
} catch (error) {
console.error("An error occurred while fetching data:", error);
}
}, 1000);
}
- Add a function to render card data
function renderCardData(cardData) {
document.getElementById("dynamicContent").innerHTML = `
<p class="text-white text-xl m-10 ml-14">${cardData.number}</p>
<p class="text-white text-lg text-left">${cardData.date}</p>
<p class="text-white text-lg text-left">${cardData.name}</p>
${cardData.cvv ? `<p class="text-white text-lg text-right">${cardData.cvv}</p>` : ""}
`;
}
- Add a function to display/hide flip card message
function displayFlipCardMessage() {
document.getElementById("flip-card-message").style.display = "flex";
}
function hideFlipCardMessage() {
document.getElementById("flip-card-message").style.display = "none";
}
- Initialize Lens
window.startCCWasm = async () => {
try {
await VeryfiLens.initCC(sessionToken, CLIENT_ID);
pollCardData();
} catch (error) {
console.error("Error starting Wasm Lens:", error);
}
};
- Call the
startCCWasm
function
Add styles (Optional)
.card-wrapper {
display: none;
position: absolute;
display: flex;
flex-direction: column;
z-index: 900;
margin-left: 3%;
}
.card-container {
display: none;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
pointer-events: none;
z-index: 60;
margin-top: 40vh;
}
.card {
display: none;
border: 8px solid white;
width: 360px;
height: 200px;
border-radius: 12px;
padding: 16px;
background-color: rgba(0, 0, 0, 0.3);
position: relative;
overflow: hidden;
margin-bottom: 1rem;
}
.card-submit-button {
display:none;
z-index: 60;
height: 50px;
width: 200px;
margin-top: 5px;
background-color: #00FA6C;
color: white;
font-weight: bold;
text-align: center;
}
#dynamicContent p {
color: white;
margin: 10px 0;
font-size: 20px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.flip-card-message {
display: none;
color: white;
font-size: 25px;
font-weight: bold;
position: absolute;
top: 75%;
left: 53%;
transform: translate(-50%, -50%);
z-index: 1000;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}