Intake Forms
Patient onboarding forms for GLP-1, NAD+, and Microdose products.
Overview
YourEra operates three separate React SPA intake forms, each tailored to a specific
product line. All three are hosted on CloudFront/S3 at intake.hisera.com
with product-specific paths.
Deployment
| Product | Path | Steps |
|---|---|---|
| GLP-1 Weightloss | /start-online-visit/glp-1/ |
19 |
| NAD+ Wellness | /start-online-visit/nad/ |
23 |
| Microdose | /start-online-visit/micro/ |
22 |
Infrastructure
| Component | Value |
|---|---|
| S3 Bucket | hisera-static-assets/intake/start-online-visit/ |
| CloudFront | E2MF26IKHV4PLZ (d3stenc5l9iicr.cloudfront.net) |
| API | intake-api.hisera.com (Intake Gateway) |
| Deploy | scripts/deploy-intakes.sh --deploy (tests, build, S3 sync, CF invalidation) |
intake.yourera.com points to Vercel/Bask (CNAME cname.vercel-dns.com) —
NEVER TOUCH this record. intake.hisera.com points to CloudFront.
Architecture (Per Intake)
┌───────────────────────────────────────┐
│ intake.hisera.com (CloudFront + S3) │
│ React SPA (Vite) │
└────────────┬──────────────────────────┘
│
┌────────────▼──────────────────────────┐
│ intake-api.hisera.com (ECS) │
│ Intake Gateway │
├───────────┬───────────┬───────────────┤
│ Stripe │ Canvas │ Google │
│ Payment │ Patient │ Places │
│ API │ Creation │ Autocomplete │
└───────────┴───────────┴───────────────┘
GLP-1 Weightloss
The GLP-1 intake is the primary product intake with 19 steps. It collects patient demographics, medical history, body metrics, and payment information for Semaglutide and Tirzepatide prescriptions.
Step Flow (19 Steps)
| # | Step | Description |
|---|---|---|
| 1 | Goal | Weight loss goal selection |
| 2 | Account | Email + password (Google OAuth or email OTP) |
| 3 | DOB | Date of birth (auto-formatted MM-DD-YYYY) |
| 4 | Sex | Biological sex at birth |
| 5 | Phone | Phone number (auto-formatted) |
| 6 | Medications | Current GLP-1 or related medications |
| 7 | Metrics | Height and weight for BMI calculation |
| 8 | Address | Shipping address with Google Places autocomplete |
| 9 | Checkout | Plan selection and Stripe payment |
| 10-17 | Medical Questions | Health history, allergies, conditions, pregnancy, thyroid |
| 18 | ID Upload | Government ID scan (barcode or OCR) |
| 19 | Done | Confirmation and scheduling prompt |
NAD+ Wellness
The NAD+ intake is a 23-step form for the NAD+ 200 mg/mL subcutaneous injection wellness protocol. It includes unique screening steps for G6PD deficiency, CKD, and cancer treatment history that are not present in the other intakes.
Unique Steps
- G6PD/CKD Screening — Screens for glucose-6-phosphate dehydrogenase deficiency and chronic kidney disease (contraindications)
- Cancer Treatment — Active cancer treatment screening (contraindication for NAD+)
- Informed Consent — Detailed consent for subcutaneous injection protocol
- Primary Reason — Why the patient is seeking NAD+ therapy (anti-aging, energy, cognitive, etc.)
- Symptoms — Current symptoms that NAD+ may address
Product Details
| Field | Value |
|---|---|
| Product | NAD+ 200 mg/mL for Subcutaneous Injection, 5 mL Vial |
| Supplier | Galleria (GMP) |
| Boothwyn SKU | 12832 |
| Program | 12-week protocol |
| Price | $170/month |
Microdose
The Microdose intake is a 22-step form with unique medication preference selection and a diabetes medications disqualifier step.
Unique Steps
- Diabetes Medications — Screens for current diabetes medications (disqualifier for microdose program)
- Medication Preference — Patient selects their preferred medication form factor
Shared Steps
The remaining steps follow the same pattern as the GLP-1 intake: account creation, demographics (DOB, sex, phone), address with autocomplete, payment checkout, medical history questions, ID upload, and confirmation.
Payment
All three intakes use Stripe for payment processing. The checkout step uses
Stripe's PaymentElement (embedded, not redirect) to collect card details
and create a SetupIntent that saves the card for future charges.
Payment Flow
- Intake frontend requests a
SetupIntentfrom the Intake Gateway - Stripe
PaymentElementrenders in-page for card collection - Patient enters card details and confirms
- Card is saved as a Stripe
PaymentMethodattached to the customer - PaymentMethod ID is stored in the Integration Service
payment_holdstable - Card is charged later when the prescription is approved (via orchestrator)
Discount Codes
Patients can enter a discount code during checkout. The code is validated against
Stripe coupons via the POST /validate-coupon endpoint on the Intake Gateway.
The coupon ID in Stripe must match the code the patient enters.
Authentication
The intake forms support two authentication methods for the account creation step. The deployed (production) version and development version use different providers.
Production (Deploy Repo)
- Google OAuth — Google Sign-In for one-click account creation
- Email OTP — Email verification code for non-Google users
Development (Dev Repo)
- Clerk — Clerk authentication provider for local development
yourera-ios-app/react-intakes/) and deploy repo
(yourEra-intake/) have significantly diverged. The deploy repo uses
encryptAndStore/retrieveAndDecrypt (AES-256-GCM), GoogleSignIn,
GTM, and ALLOWED_STATES. Always port changes manually between repos.
Draft Persistence
All intake forms implement client-side draft persistence using localStorage.
Patient progress is saved automatically as they fill out the form, so they can resume
later if they close the browser.
Implementation
- Debounced Save — Form state is saved to
localStoragewith a 1-second debounce to avoid excessive writes - beforeunload Flush — A
beforeunloadevent handler flushes any pending debounced save to ensure data is preserved on page close - Local useState — Each field uses local
useStatewith a generation counter to handle async state correctly - Debounced Fetch — Address autocomplete uses a 300ms debounced fetch to avoid excessive Google Places API calls
Debounce Utility
// utils/debounce.js
export function createDebouncedFn(fn, ms) {
let timer;
const debouncedFn = (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), ms);
};
const cancelFn = () => clearTimeout(timer);
return [debouncedFn, cancelFn];
}
ID Verification
The ID upload step supports multiple methods for capturing and verifying government-issued identification. The system attempts barcode scanning first, falls back to OCR, and allows manual upload as a last resort.
Verification Methods
-
PDF417 Barcode Scan — Uses
zxing-wasmto scan the PDF417 barcode on the back of US driver's licenses. This is the fastest and most accurate method. -
OCR Fallback — If barcode scanning fails,
tesseract-wasmperforms optical character recognition on the ID image to extract text fields. - Manual Upload — If both automated methods fail, the patient can manually upload a photo of their ID. OCR is attempted on the uploaded image.
Extracted Fields
| Field | Source | Usage |
|---|---|---|
firstName |
Barcode / OCR | Cross-referenced with intake name |
lastName |
Barcode / OCR | Cross-referenced with intake name |
dateOfBirth |
Barcode / OCR | Cross-referenced with intake DOB |
address |
Barcode / OCR | Cross-referenced with shipping address |
expirationDate |
Barcode / OCR | Validated to ensure ID is not expired |
NSCameraUsageDescription in Info.plist (iOS) or camera permissions (web).
Camera uses imperative UIKit presentation via CameraManager on iOS.