@enterestos/sdk
v0.1.2
Published
Track form submissions after submit. AI intent classification, priority scoring, and next best action for every submission. Works with any project built in Lovable, Bolt, Cursor, Claude Code, v0, Next.js, React, SvelteKit, or plain HTML. No form rebuild r
Downloads
27
Maintainers
Keywords
Readme
EnterestOS SDK
Track what happens after every form submission. Understand intent. Know what to do next.
EnterestOS sits between your form and your inbox. When someone submits your form, EnterestOS reads the submission, classifies the intent, scores the priority, and surfaces one clear next action — so you always know which submission matters most and what to do about it.
Works with any project built in Lovable, Bolt, Cursor, Claude Code, v0, Next.js, React, SvelteKit, or plain HTML. No form rebuild. No CRM setup. One line after submit.
Form submits → trackResponse() fires → EnterestOS Inbox
↓
AI reads the submission
Classifies intent
Scores priority (1–5)
Writes AI summary
Surfaces Next Best Action
(Schedule Demo / Confirm Booking / Follow Up)When to use this SDK
Use EnterestOS when the project has any of these:
- A contact form, demo request form, booking form, waitlist, or lead capture
- Form submissions going to email with no follow-up system
- A solo founder or small team who needs to know which submission to reply to first
- Multiple projects with forms — one inbox to track all of them
- Built with Lovable, Bolt, Cursor, Claude Code, v0, Replit, or any AI builder
- Built with Next.js, React, SvelteKit, Astro, Vite, or plain HTML
Do not use if the project only needs raw form data storage with no response workflow.
Install
npm install @enterestos/sdkpnpm add @enterestos/sdkyarn add @enterestos/sdkSetup — 2 minutes
Step 1: Get your project key
- Go to enterestos.com — signup takes under a minute
- Create a new project — upload a screenshot of the form or paste the form code
- EnterestOS generates one project key and an AI implementation prompt
- Copy the project key into your environment variables
# Vite / Lovable / Bolt / SvelteKit / Astro
VITE_ENTERESTOS_PROJECT_KEY=eos_live_xxxxxxxxxxxx
# Next.js (client-side)
NEXT_PUBLIC_ENTERESTOS_PROJECT_KEY=eos_live_xxxxxxxxxxxx
# Next.js / Node (server-side — keep private, never expose in client)
ENTERESTOS_PROJECT_KEY=eos_live_xxxxxxxxxxxxYou only need the project key for normal SDK usage. EnterestOS uses that key to authenticate the request and route the submission to the right project automatically. A separate project ID is not required unless support asks you to use one for an advanced migration or compatibility case.
Step 2: Add one line after your existing submit handler
Your existing form code does not change. EnterestOS fires after your current success handler.
import { createEnterestOS } from "@enterestos/sdk";
const enterestos = createEnterestOS({
projectKey: import.meta.env.VITE_ENTERESTOS_PROJECT_KEY,
});
// After your existing submit success:
await enterestos.trackResponse({
type: "contact_form",
payload: { ...formData },
});Step 3: Send one test submission. EnterestOS connects automatically.
No manual verification. Submit your form once and the project connects. Your inbox is live.
AI Tool Implementation Prompt
If you are using Lovable, Bolt, Cursor, Claude Code, v0, Windsurf, Copilot, or any AI coding assistant — paste this prompt to implement EnterestOS in one pass:
Add EnterestOS form submission tracking to this project.
1. Install the SDK:
npm install @enterestos/sdk
2. Add environment variable:
- Vite/Lovable/Bolt: VITE_ENTERESTOS_PROJECT_KEY=your_key
- Next.js client: NEXT_PUBLIC_ENTERESTOS_PROJECT_KEY=your_key
- Server-side: ENTERESTOS_PROJECT_KEY=your_key
3. Import and initialise (once, at module level):
import { createEnterestOS } from "@enterestos/sdk";
const enterestos = createEnterestOS({
projectKey: import.meta.env.VITE_ENTERESTOS_PROJECT_KEY,
});
4. After the existing form submit success handler, add:
await enterestos.trackResponse({
type: "[form_type]",
payload: { ...all form fields },
metadata: {
page_url: window.location.href,
referrer: document.referrer,
utm_source: new URLSearchParams(window.location.search).get("utm_source"),
},
});
5. Rules:
- Do NOT modify existing form logic
- trackResponse() fires AFTER existing success handler
- Use fire-and-forget (no await) if tracking must not block UX
- Include ALL form fields in payload — more fields = better AI classification
- Call enterestos.testConnection() to verify setup before going live
6. form_type examples:
"contact_form" | "demo_request" | "booking_request" |
"property_enquiry" | "waitlist_signup" | "support_request"Integration Patterns
React / Next.js — contact form
import { createEnterestOS } from "@enterestos/sdk";
const enterestos = createEnterestOS({
projectKey: process.env.NEXT_PUBLIC_ENTERESTOS_PROJECT_KEY!,
});
async function handleSubmit(formData: FormData) {
// Your existing submit logic — unchanged
await sendToYourBackend(formData);
// Add after your existing success handler
await enterestos.trackResponse({
type: "contact_form",
payload: {
name: formData.get("name") as string,
email: formData.get("email") as string,
message: formData.get("message") as string,
},
metadata: {
page_url: window.location.href,
referrer: document.referrer,
},
});
}Demo request form
await enterestos.trackResponse({
type: "demo_request",
payload: {
name: formData.name,
email: formData.email,
company: formData.company,
team_size: formData.teamSize,
message: formData.message,
},
metadata: { page_url: window.location.href },
});Booking / appointment form
await enterestos.trackResponse({
type: "booking_request",
payload: {
name: formData.name,
email: formData.email,
phone: formData.phone,
date: formData.preferredDate,
time: formData.preferredTime,
notes: formData.notes,
},
});Property / real estate enquiry
await enterestos.trackResponse({
type: "property_enquiry",
payload: {
name: formData.name,
email: formData.email,
phone: formData.phone,
property_address: formData.propertyAddress,
viewing_date: formData.viewingDate,
message: formData.message,
},
});Waitlist / early access signup
await enterestos.trackResponse({
type: "waitlist_signup",
payload: {
email: formData.email,
name: formData.name,
use_case: formData.useCase,
},
metadata: { source: "landing_page" },
});Lovable / Bolt project (Vite-based)
import { createEnterestOS } from "@enterestos/sdk";
const enterestos = createEnterestOS({
projectKey: import.meta.env.VITE_ENTERESTOS_PROJECT_KEY,
});
// In your form submit handler
const handleSubmit = async (values: FormValues) => {
// Your existing Lovable/Bolt logic — unchanged
await yourExistingHandler(values);
// Add EnterestOS after
enterestos.trackResponse({
type: "contact_form",
payload: values,
metadata: {
page_url: window.location.href,
referrer: document.referrer,
utm_source: new URLSearchParams(window.location.search).get("utm_source") ?? undefined,
},
}).catch(console.error); // fire-and-forget
};Next.js App Router — Server Action
// app/actions.ts
"use server";
import { createEnterestOS } from "@enterestos/sdk";
const enterestos = createEnterestOS({
projectKey: process.env.ENTERESTOS_PROJECT_KEY!,
});
export async function submitContactForm(formData: FormData) {
const data = {
name: formData.get("name") as string,
email: formData.get("email") as string,
message: formData.get("message") as string,
};
// Your existing server action logic
await saveToDatabase(data);
await sendNotificationEmail(data);
// Add EnterestOS after
await enterestos.trackResponse({
type: "contact_form",
payload: data,
});
}SvelteKit
// +page.server.ts
import { createEnterestOS } from "@enterestos/sdk";
const enterestos = createEnterestOS({
projectKey: import.meta.env.VITE_ENTERESTOS_PROJECT_KEY,
});
export const actions = {
default: async ({ request }) => {
const data = Object.fromEntries(await request.formData());
// Your existing action logic
await yourExistingHandler(data);
// Add EnterestOS after
await enterestos.trackResponse({
type: "contact_form",
payload: data,
});
return { success: true };
},
};Plain HTML / Vanilla JS
<script type="module">
import { createEnterestOS } from "https://esm.sh/@enterestos/sdk";
const enterestos = createEnterestOS({
projectKey: "your_project_key_here",
});
document.getElementById("contact-form").addEventListener("submit", async (e) => {
e.preventDefault();
const data = Object.fromEntries(new FormData(e.target));
// Your existing logic
await yourExistingHandler(data);
// Add EnterestOS after
enterestos.trackResponse({
type: "contact_form",
payload: data,
metadata: { page_url: window.location.href, referrer: document.referrer },
}).catch(console.error);
});
</script>Page Context — Capture Automatically
Pass page context so EnterestOS knows where submissions come from. Improves intent classification and NBA recommendations. Zero config required — just include this helper.
function getPageContext() {
const params = new URLSearchParams(window.location.search);
return {
page_url: window.location.href,
page_title: document.title,
referrer: document.referrer,
utm_source: params.get("utm_source") ?? undefined,
utm_medium: params.get("utm_medium") ?? undefined,
utm_campaign: params.get("utm_campaign") ?? undefined,
utm_content: params.get("utm_content") ?? undefined,
};
}
await enterestos.trackResponse({
type: "demo_request",
payload: formData,
metadata: getPageContext(),
});EnterestOS can then surface: "Submitted from your pricing page — came from Product Hunt 8 minutes after your launch post."
Multiple Projects
EnterestOS is designed for builders running multiple projects simultaneously. Each project gets its own key. You do not need to pass project IDs in the SDK. All projects appear in one unified inbox sorted by urgency.
// Project 1 — SaaS landing page
const saasEOS = createEnterestOS({ projectKey: process.env.SAAS_KEY! });
// Project 2 — Booking site
const bookingEOS = createEnterestOS({ projectKey: process.env.BOOKING_KEY! });
// Project 3 — Property finder
const propertyEOS = createEnterestOS({ projectKey: process.env.PROPERTY_KEY! });Non-Blocking Usage
trackResponse() should not block your user-facing response. If EnterestOS fails, your form submit still succeeds.
// Fire-and-forget — recommended for client-side forms
enterestos.trackResponse({ type: "contact_form", payload: data })
.catch(console.error);
// Awaited — use when you need confirmation (server actions, API routes)
await enterestos.trackResponse({ type: "contact_form", payload: data });What EnterestOS Does With the Submission
Every trackResponse() call produces:
| Output | Description | |--------|-------------| | Intent | What the person actually wants: demo, booking, support, enquiry, waitlist | | Priority | Urgency score 1–5 based on timeline language, team size, competitive signals | | AI Summary | Plain-English summary ready to read at a glance | | Next Best Action | One specific action: Schedule Demo, Confirm Booking, Follow Up, Archive | | Workflow State | Reply → Waiting → Done | | Confidence Score | How confident EnterestOS is in the NBA (e.g. 96%) |
The founder opens the inbox and immediately knows what to do — without reading the raw submission.
API Reference
createEnterestOS(config)
type EnterestOSConfig = {
projectKey: string; // required — authenticates and routes to the project
projectId?: string; // optional advanced override — normally not needed
baseUrl?: string; // optional — defaults to EnterestOS cloud
timeoutMs?: number; // optional — default 10000ms
retries?: number; // optional — default 3
headers?: Record<string, string>; // optional
fetch?: typeof fetch; // optional — custom fetch
};For almost every integration, pass only projectKey. The SDK sends it as the public credential, and EnterestOS resolves the owning project from that key.
trackResponse(payload)
type TrackResponsePayload = {
type: string; // form type — e.g. "contact_form"
payload: Record<string, unknown>; // all form field values
metadata?: Record<string, unknown>; // page context, UTM params, source
};
// Returns Promise<void>trackEvent(payload) — legacy
type TrackEventPayload = {
eventType: string;
payload: Record<string, unknown>;
metadata?: Record<string, unknown>;
};Use trackResponse() for all new integrations.
testConnection()
Verifies the project key is valid. Call during setup before going live.
await enterestos.testConnection();
// Throws EnterestOSError if connection failsbuildEnterestOSHeaders()
Returns auth headers. For custom fetch or server-side proxy implementations.
Error Handling
import { EnterestOSError } from "@enterestos/sdk";
try {
await enterestos.trackResponse({ type: "contact_form", payload: data });
} catch (error) {
if (error instanceof EnterestOSError) {
// Log and continue — never let tracking block the form submit
console.error("EnterestOS:", error.code, error.message);
}
}Error Codes
| Code | Cause | Fix |
|------|-------|-----|
| PROJECT_KEY_REQUIRED | projectKey not provided | Add to createEnterestOS() config |
| INVALID_PROJECT_KEY | Key invalid or revoked | Check project settings at enterestos.com |
| RESPONSE_TYPE_REQUIRED | type missing | Add type to trackResponse() |
| PAYLOAD_REQUIRED | payload empty or missing | Include form fields in payload |
| NETWORK_ERROR | Request failed after retries | SDK retries automatically |
| RATE_LIMITED | Too many requests | SDK retries with backoff |
Verify Your Integration
After adding trackResponse(), submit your form once. Within seconds, the submission appears in your EnterestOS inbox at enterestos.com with:
- AI summary
- Intent classification
- Priority score
- Confidence level
- Next Best Action
If it doesn't appear:
- Run
await enterestos.testConnection()— verifies the project key - Check browser console for
EnterestOSError - Confirm
trackResponse()fires after a successful submit, not before - Verify the environment variable is accessible in your runtime
TypeScript
Full TypeScript support included. No @types package needed.
import type { EnterestOSConfig, TrackResponsePayload } from "@enterestos/sdk";License
MIT — enterestos.com
