<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alexander Polozhevets</title>
    <description>The latest articles on DEV Community by Alexander Polozhevets (@polozhevets).</description>
    <link>https://dev.to/polozhevets</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3317397%2Fc0041cd2-df9c-4f11-bfcc-2437330173b5.jpg</url>
      <title>DEV Community: Alexander Polozhevets</title>
      <link>https://dev.to/polozhevets</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/polozhevets"/>
    <language>en</language>
    <item>
      <title>Build a Landing Page with ChatGPT, Deploy on Cloudflare and Collect Leads (No Backend)</title>
      <dc:creator>Alexander Polozhevets</dc:creator>
      <pubDate>Sun, 31 May 2026 13:01:57 +0000</pubDate>
      <link>https://dev.to/polozhevets/build-a-landing-page-with-chatgpt-deploy-on-cloudflare-and-collect-leads-no-backend-k76</link>
      <guid>https://dev.to/polozhevets/build-a-landing-page-with-chatgpt-deploy-on-cloudflare-and-collect-leads-no-backend-k76</guid>
      <description>&lt;p&gt;You can ship a professional landing page in under an hour — no design degree, no backend, no &lt;code&gt;mailto:&lt;/code&gt; links that vanish in spam.&lt;/p&gt;

&lt;p&gt;This guide walks through three free tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://chatgpt.com/" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Generate HTML and copy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://pages.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare Pages&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Host the site (HTTPS, global CDN)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://formcare.io" rel="noopener noreferrer"&gt;FormCare&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Receive and store form submissions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What you'll have when you're done:&lt;/strong&gt; a live URL, a contact form that saves leads to a dashboard, and optional email alerts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time:&lt;/strong&gt; about 45–60 minutes on your first run.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the pieces fit together
&lt;/h2&gt;

&lt;p&gt;Static pages cannot save form data on their own. When someone clicks &lt;strong&gt;Send&lt;/strong&gt;, the browser POSTs to a URL in your form's &lt;code&gt;action&lt;/code&gt; attribute. FormCare receives that POST, stores the fields, and can email you — while Cloudflare only serves HTML files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Visitor → Cloudflare Pages (HTML/CSS)
              ↓
         Contact form POST
              ↓
         FormCare API → Dashboard + email
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You never write a server, database, or API route on Cloudflare.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before you start
&lt;/h2&gt;

&lt;p&gt;Create free accounts (no credit card needed for FormCare to test):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://chatgpt.com" rel="noopener noreferrer"&gt;ChatGPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dash.cloudflare.com/sign-up" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://formcare.io/register" rel="noopener noreferrer"&gt;FormCare&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; — recommended for Cloudflare Pages Git deploys&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 1 — Build the page
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Generate HTML with ChatGPT
&lt;/h3&gt;

&lt;p&gt;Ask ChatGPT for &lt;strong&gt;one self-contained HTML file&lt;/strong&gt; (inline CSS, no build step). Use the placeholder &lt;code&gt;YOUR_ENDPOINT_SLUG&lt;/code&gt; in the form URL for now — you'll replace it in Step 2.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Copy this prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a modern SaaS landing page in ONE HTML file (inline CSS, no external dependencies).

Include:
- Hero section with headline and primary CTA button
- Features section (3–4 items)
- Simple pricing section
- Contact form section at the bottom
- Responsive layout (mobile-friendly)
- Clean, modern CSS

For the contact form, use EXACTLY this setup:
- form method="POST"
- form action="https://formcare.io/api/submit/YOUR_ENDPOINT_SLUG"
- Fields: name (text, required), email (email, required), message (textarea, required)
- Each input must have a name attribute matching the field (name, email, message)
- A submit button
- Accessible labels for every field

Do not use JavaScript for form submission. Use a standard HTML form POST only.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the output as &lt;code&gt;index.html&lt;/code&gt; in a folder, e.g. &lt;code&gt;my-landing-page/&lt;/code&gt;. Open it in your browser to check the layout. The form will not work until you add a real FormCare slug in Step 2.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Field names become column labels in FormCare. Keep them simple: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Minimal form example&lt;/strong&gt; (if you prefer to paste code yourself):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt;
  &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://formcare.io/api/submit/YOUR_ENDPOINT_SLUG"&lt;/span&gt;
  &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Message&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="na"&gt;rows=&lt;/span&gt;&lt;span class="s"&gt;"5"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"source"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"cloudflare-landing-page"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Send message&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 2: Create a FormCare endpoint and wire the form
&lt;/h3&gt;

&lt;p&gt;In FormCare you create an &lt;strong&gt;endpoint&lt;/strong&gt; (not a drag-and-drop form builder). Each endpoint gets a unique slug in its submit URL.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://formcare.io/register" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; and open &lt;strong&gt;&lt;a href="https://formcare.io/endpoints" rel="noopener noreferrer"&gt;Endpoints&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create endpoint&lt;/strong&gt; (e.g. name it &lt;code&gt;Landing Page – Contact&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Copy the &lt;strong&gt;submit URL&lt;/strong&gt; from the endpoint card:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   https://formcare.io/api/submit/QVum2Ts1Kk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;In &lt;code&gt;index.html&lt;/code&gt;, set the form &lt;code&gt;action&lt;/code&gt; to that full URL (or replace only &lt;code&gt;YOUR_ENDPOINT_SLUG&lt;/code&gt; with the slug at the end).&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;(Recommended)&lt;/em&gt; In endpoint settings:

&lt;ul&gt;
&lt;li&gt;Enable &lt;strong&gt;email notifications&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;custom redirect URL&lt;/strong&gt; after you deploy (Step 5)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Copy the slug from the dashboard — do not invent your own.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Full reference: &lt;a href="https://formcare.io/docs" rel="noopener noreferrer"&gt;FormCare documentation&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Add a thank-you page (recommended)
&lt;/h3&gt;

&lt;p&gt;After a successful POST, FormCare redirects the visitor (HTTP 302). A dedicated thank-you page feels clearer than sending people back to the form.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;thank-you.html&lt;/code&gt; next to &lt;code&gt;index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Thank you&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"max-width: 32rem; margin: 4rem auto; padding: 0 1.5rem; font-family: system-ui, sans-serif;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Thanks for reaching out!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;We received your message and will get back to you soon.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;← Back to home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set &lt;strong&gt;Custom redirect URL&lt;/strong&gt; in FormCare once you know your live site URL (Step 6). If you skip this, FormCare falls back to the page the user came from (&lt;code&gt;Referer&lt;/code&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2 — Deploy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 4: Push to GitHub
&lt;/h3&gt;

&lt;p&gt;Cloudflare Pages deploys from Git. In your project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add index.html thank-you.html
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add landing page with FormCare contact form"&lt;/span&gt;
git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
git remote add origin https://github.com/YOUR_USERNAME/my-landing-page.git
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your repo can be as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/
├── index.html
└── thank-you.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If ChatGPT created extra files (e.g. separate CSS), add them with &lt;code&gt;git add .&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 5: Deploy on Cloudflare Pages
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://dash.cloudflare.com" rel="noopener noreferrer"&gt;Cloudflare dashboard&lt;/a&gt; → &lt;strong&gt;Workers &amp;amp; Pages&lt;/strong&gt; → &lt;strong&gt;Create&lt;/strong&gt; → &lt;strong&gt;Pages&lt;/strong&gt; → &lt;strong&gt;Connect to Git&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Authorize GitHub and select your repository.&lt;/li&gt;
&lt;li&gt;Build settings for plain HTML:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework preset&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build command&lt;/td&gt;
&lt;td&gt;&lt;em&gt;(empty)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build output directory&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Save and Deploy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In a few minutes you get a URL like &lt;code&gt;https://my-landing-page.pages.dev&lt;/code&gt;. See the &lt;a href="https://developers.cloudflare.com/pages/get-started/" rel="noopener noreferrer"&gt;Pages getting started guide&lt;/a&gt; if you need more detail.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 6: Connect FormCare to your live URL and test
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Endpoints&lt;/strong&gt; → your endpoint → set &lt;strong&gt;Custom redirect URL&lt;/strong&gt; to
&lt;code&gt;https://my-landing-page.pages.dev/thank-you.html&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;email notifications&lt;/strong&gt; if you have not already.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;live&lt;/strong&gt; &lt;code&gt;.pages.dev&lt;/code&gt; URL (not the local file).&lt;/li&gt;
&lt;li&gt;Submit a test message.&lt;/li&gt;
&lt;li&gt;Confirm it appears in the &lt;a href="https://formcare.io/dashboard" rel="noopener noreferrer"&gt;FormCare dashboard&lt;/a&gt; within seconds.&lt;/li&gt;
&lt;li&gt;Check your inbox if notifications are on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Pre-launch checklist:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Done?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Form &lt;code&gt;action&lt;/code&gt; uses your real slug, not &lt;code&gt;YOUR_ENDPOINT_SLUG&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;☐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test submitted from the published Cloudflare URL&lt;/td&gt;
&lt;td&gt;☐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Submission visible in FormCare dashboard&lt;/td&gt;
&lt;td&gt;☐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redirect lands on &lt;code&gt;thank-you.html&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;☐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Email notification received (if enabled)&lt;/td&gt;
&lt;td&gt;☐&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;More help: &lt;a href="https://formcare.io/blog/html-form-backend-setup-guide" rel="noopener noreferrer"&gt;HTML form backend setup guide&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3 — Polish (optional)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Custom domain
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Cloudflare Pages → your project → &lt;strong&gt;Custom domains&lt;/strong&gt; → add your domain.&lt;/li&gt;
&lt;li&gt;Follow DNS instructions (easiest when the domain is already on Cloudflare).&lt;/li&gt;
&lt;li&gt;SSL is automatic.&lt;/li&gt;
&lt;li&gt;Update the FormCare &lt;strong&gt;custom redirect URL&lt;/strong&gt; to use the new domain, e.g.
&lt;code&gt;https://yourproduct.com/thank-you.html&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Improve copy and layout with ChatGPT
&lt;/h3&gt;

&lt;p&gt;Once the form pipeline works, iterate safely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Improve this landing page HTML for conversions. Add:
- Social proof (logos or stats)
- Short testimonials
- FAQ section
- Stronger call-to-action in the hero

Keep the contact form action URL and field names unchanged.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never let ChatGPT change your FormCare &lt;code&gt;action&lt;/code&gt; URL or input &lt;code&gt;name&lt;/code&gt; attributes unless you mean to.&lt;/p&gt;




&lt;h3&gt;
  
  
  SEO basics
&lt;/h3&gt;

&lt;p&gt;Fast static HTML on Cloudflare already helps Core Web Vitals. Add the essentials in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Your Product – Short benefit-driven headline&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt;
  &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;
  &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"One sentence: what you offer and who it is for. Include your main keyword naturally."&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://yourproduct.com/"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Your Product – Short headline"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Same or similar to meta description."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yourproduct.com/"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quick rules:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; (hero headline); section titles as &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Wrap content in &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;footer&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;alt&lt;/code&gt; text on every meaningful image&lt;/li&gt;
&lt;li&gt;Title ~50–60 characters; description ~150–160 characters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add &lt;code&gt;robots.txt&lt;/code&gt; and &lt;code&gt;sitemap.xml&lt;/code&gt; next to &lt;code&gt;index.html&lt;/code&gt;, commit, and push. Update URLs when you move from &lt;code&gt;.pages.dev&lt;/code&gt; to a custom domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;robots.txt&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-agent: *
Allow: /

Sitemap: https://yourproduct.com/sitemap.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;sitemap.xml&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;urlset&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://sitemaps.org/schemas/sitemap/0.9"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;loc&amp;gt;&lt;/span&gt;https://yourproduct.com/&lt;span class="nt"&gt;&amp;lt;/loc&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;changefreq&amp;gt;&lt;/span&gt;monthly&lt;span class="nt"&gt;&amp;lt;/changefreq&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;priority&amp;gt;&lt;/span&gt;1.0&lt;span class="nt"&gt;&amp;lt;/priority&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/urlset&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Submit the sitemap in &lt;a href="https://search.google.com/search-console" rel="noopener noreferrer"&gt;Google Search Console&lt;/a&gt; after verifying your domain. Test speed with &lt;a href="https://pagespeed.web.dev/" rel="noopener noreferrer"&gt;PageSpeed Insights&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ChatGPT SEO prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Optimize this landing page HTML for SEO. Add or fix:
- title tag (under 60 characters)
- meta description (under 160 characters)
- canonical link tag
- Open Graph tags
- semantic HTML (header, main, section, footer)
- alt text on images
- one h1 only, proper h2 hierarchy

Do not change the contact form action URL or input name attributes.
Target keyword: [YOUR KEYWORD]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  File uploads and spam protection
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Attachments&lt;/strong&gt; — add &lt;code&gt;enctype="multipart/form-data"&lt;/code&gt; and a file input:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://formcare.io/api/submit/YOUR_ENDPOINT_SLUG"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt; &lt;span class="na"&gt;enctype=&lt;/span&gt;&lt;span class="s"&gt;"multipart/form-data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- name, email, message --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"resume"&lt;/span&gt; &lt;span class="na"&gt;accept=&lt;/span&gt;&lt;span class="s"&gt;".pdf,.doc,.docx"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://formcare.io/docs#file-uploads" rel="noopener noreferrer"&gt;file upload docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Honeypot&lt;/strong&gt; (optional extra layer — FormCare also has built-in protection):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.fc-honeypot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-9999px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"fc-honeypot"&lt;/span&gt; &lt;span class="na"&gt;tabindex=&lt;/span&gt;&lt;span class="s"&gt;"-1"&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"off"&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Likely cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Form does nothing / 404&lt;/td&gt;
&lt;td&gt;Placeholder slug in &lt;code&gt;action&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Paste your real endpoint URL from FormCare&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No submission in dashboard&lt;/td&gt;
&lt;td&gt;Testing local file only&lt;/td&gt;
&lt;td&gt;Test from the live &lt;code&gt;.pages.dev&lt;/code&gt; URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wrong redirect after submit&lt;/td&gt;
&lt;td&gt;Redirect URL not set&lt;/td&gt;
&lt;td&gt;Set custom redirect in endpoint settings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No emails&lt;/td&gt;
&lt;td&gt;Notifications off&lt;/td&gt;
&lt;td&gt;Enable per-endpoint email alerts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Missing or duplicate fields&lt;/td&gt;
&lt;td&gt;ChatGPT renamed &lt;code&gt;name&lt;/code&gt; attributes&lt;/td&gt;
&lt;td&gt;Keep &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Still stuck? &lt;a href="https://formcare.io/docs" rel="noopener noreferrer"&gt;FormCare docs&lt;/a&gt; · &lt;a href="https://formcare.io/blog/wix-formcare-integration-guide" rel="noopener noreferrer"&gt;Wix + FormCare guide&lt;/a&gt; (same HTML POST pattern)&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do I need a backend on Cloudflare?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No. Pages serves static files. The form POST goes to &lt;code&gt;formcare.io/api/submit/...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this good for SEO?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, once you add title, description, headings, canonical URL, and submit a sitemap. Static HTML on Cloudflare loads fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React or Next.js?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This guide uses plain HTML. JS apps can POST JSON instead — see &lt;a href="https://formcare.io/docs#ajax-json" rel="noopener noreferrer"&gt;AJAX integration&lt;/a&gt;. HTML forms do not need CORS; SPAs may need your domain allowed in endpoint settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does FormCare cost?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Free tier includes a monthly submission allowance; no card required to test. Paid plans apply when you exceed free limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is form data secure?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Submissions use HTTPS. Cloudflare serves your site over HTTPS by default. See &lt;a href="https://formcare.io/privacy" rel="noopener noreferrer"&gt;privacy&lt;/a&gt; for retention details.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this stack works
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ChatGPT&lt;/th&gt;
&lt;th&gt;Cloudflare Pages&lt;/th&gt;
&lt;th&gt;FormCare&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Fast HTML and copy&lt;/td&gt;
&lt;td&gt;Free hosting, Git deploy, HTTPS&lt;/td&gt;
&lt;td&gt;Form POSTs without a server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You avoid&lt;/td&gt;
&lt;td&gt;Hiring a designer day one&lt;/td&gt;
&lt;td&gt;Hosting bills for small sites&lt;/td&gt;
&lt;td&gt;Databases, APIs, &lt;code&gt;mailto:&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Good fit for SaaS founders validating ideas, indie hackers, agencies running campaign pages, and anyone learning static sites + form backends.&lt;/p&gt;




&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Generate &lt;code&gt;index.html&lt;/code&gt; with ChatGPT
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://formcare.io/register" rel="noopener noreferrer"&gt;Create a FormCare endpoint&lt;/a&gt; and update the form &lt;code&gt;action&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Deploy to &lt;a href="https://pages.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare Pages&lt;/a&gt; and run one live test
&lt;/li&gt;
&lt;li&gt;Add SEO files and Search Console when you're ready to promote
&lt;/li&gt;
&lt;li&gt;Share the URL and collect leads
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For JSON POSTs, webhooks, and multiple forms: &lt;a href="https://formcare.io/docs" rel="noopener noreferrer"&gt;FormCare documentation&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;FormCare powers the form backend in this tutorial. The ChatGPT and Cloudflare steps work with any HTTPS endpoint that accepts HTML form POSTs.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>cloudflare</category>
      <category>vibecoding</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Save and Organize HTML Form Data from a Wix Website</title>
      <dc:creator>Alexander Polozhevets</dc:creator>
      <pubDate>Sun, 31 May 2026 10:39:43 +0000</pubDate>
      <link>https://dev.to/polozhevets/how-to-save-and-organize-html-form-data-from-a-wix-website-5hcn</link>
      <guid>https://dev.to/polozhevets/how-to-save-and-organize-html-form-data-from-a-wix-website-5hcn</guid>
      <description>&lt;p&gt;Wix makes it easy to add contact forms, lead capture widgets, and custom inputs to a site. What happens &lt;em&gt;after&lt;/em&gt; someone clicks Submit is less obvious — especially if you run multiple forms, need file attachments, or want data in one searchable place instead of scattered emails.&lt;/p&gt;

&lt;p&gt;This guide walks through practical ways to &lt;strong&gt;save&lt;/strong&gt; and &lt;strong&gt;organize&lt;/strong&gt; form data from a Wix website, whether you use native Wix Forms, a custom HTML embed, or Velo code.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Wix gives you by default
&lt;/h2&gt;

&lt;p&gt;Before reaching for third-party tools, understand the built-in path:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Destination&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wix Inbox&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Submissions from native Wix Forms land in your site dashboard&lt;/td&gt;
&lt;td&gt;Small sites, quick setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wix CRM / Contacts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Contact details sync when configured&lt;/td&gt;
&lt;td&gt;Lead follow-up inside Wix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wix CMS Collections&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Structured rows you can query in Velo or display on pages&lt;/td&gt;
&lt;td&gt;Custom apps, member areas&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a single contact form on a portfolio site, the default inbox is often enough. Teams usually look elsewhere when they need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One dashboard across &lt;strong&gt;multiple Wix sites&lt;/strong&gt; (or Wix + Webflow + static HTML)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSV exports&lt;/strong&gt;, searchable history, or long-term retention&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File uploads&lt;/strong&gt; (resumes, images) stored with the submission&lt;/li&gt;
&lt;li&gt;Custom routing (different email per form, Slack alerts, CRM sync)&lt;/li&gt;
&lt;li&gt;A stable &lt;strong&gt;HTTPS endpoint&lt;/strong&gt; they control, independent of Wix's UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Native Wix Forms also cannot set an external &lt;code&gt;action&lt;/code&gt; URL the way a plain HTML form can. Browser-side POSTs from the live site to third-party APIs often hit &lt;strong&gt;CORS&lt;/strong&gt; limits. That shapes which integration patterns actually work — covered below.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Decide how you want data organized
&lt;/h2&gt;

&lt;p&gt;Pick a primary "source of truth" before wiring anything. Mixed setups (Wix inbox &lt;em&gt;and&lt;/em&gt; a spreadsheet &lt;em&gt;and&lt;/em&gt; a webhook) create duplicates fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common organization models:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inbox / email&lt;/strong&gt; — Fast to set up; hard to search, filter, or export at scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spreadsheet&lt;/strong&gt; (Google Sheets, Airtable) — Familiar, shareable, good for non-technical teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database / collection&lt;/strong&gt; (Wix CMS, Supabase, MongoDB) — Best when you build on top of submissions in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form backend dashboard&lt;/strong&gt; — Purpose-built for submissions: structured fields, exports, notifications, optional API access.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Add &lt;strong&gt;metadata&lt;/strong&gt; early so you can filter later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jane Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jane@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Interested in your services"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wix-contact-page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"form_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main-contact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"platform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wix"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hidden fields or automation mappings for &lt;code&gt;source&lt;/code&gt;, &lt;code&gt;form_name&lt;/code&gt;, and &lt;code&gt;platform&lt;/code&gt; save hours when you have more than one form.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 1: Wix Automations (no code)
&lt;/h2&gt;

&lt;p&gt;If you use &lt;strong&gt;native Wix Forms&lt;/strong&gt;, &lt;a href="https://support.wix.com/en/article/wix-automations-an-overview" rel="noopener noreferrer"&gt;Wix Automations&lt;/a&gt; is the most accessible way to forward submissions elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Typical flow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Site dashboard → &lt;strong&gt;Automations&lt;/strong&gt; → Create automation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trigger:&lt;/strong&gt; Form submitted → select your form&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; Send webhook / HTTP request (or connect Google Sheets, email, etc.)&lt;/li&gt;
&lt;li&gt;Map each Wix field to the payload&lt;/li&gt;
&lt;li&gt;Publish and test from the &lt;strong&gt;live&lt;/strong&gt; site (Preview is not enough)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Automations run on Wix servers, so you avoid browser CORS issues. Payload shape depends on the action — always send one test submission and inspect what arrives at the destination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organizing tip:&lt;/strong&gt; Create one automation per form, or one webhook endpoint with a &lt;code&gt;form_name&lt;/code&gt; field so downstream tools can route rows correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 2: HTML embed + standard form POST
&lt;/h2&gt;

&lt;p&gt;Wix lets you add an &lt;strong&gt;HTML embed&lt;/strong&gt; with a classic &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;. Standard HTML form posts do not trigger browser CORS checks, so you can point &lt;code&gt;action&lt;/code&gt; at any HTTPS endpoint that accepts &lt;code&gt;POST&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt;
  &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://your-backend.example/submit/your-form-id"&lt;/span&gt;
  &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;
  &lt;span class="na"&gt;enctype=&lt;/span&gt;&lt;span class="s"&gt;"multipart/form-data"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
    Name
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
    Email
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
    Message
    &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"source"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"wix-html-embed"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"resume"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Send&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;enctype="multipart/form-data"&lt;/code&gt; when you need file uploads. Style the embed with your own CSS or wrap it in a Wix box so it matches your theme.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organizing tip:&lt;/strong&gt; Consistent &lt;code&gt;name&lt;/code&gt; attributes (&lt;code&gt;email&lt;/code&gt;, not &lt;code&gt;Email Field 2&lt;/code&gt;) keep columns stable in any backend or spreadsheet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 3: Velo (Wix Dev Mode) + server-side fetch
&lt;/h2&gt;

&lt;p&gt;For custom inputs, multi-step flows, or on-page success messages without a full page reload, enable &lt;strong&gt;Velo&lt;/strong&gt; and call your backend from a &lt;strong&gt;backend web module&lt;/strong&gt; (&lt;code&gt;.jsw&lt;/code&gt;). Wix recommends server-side &lt;code&gt;fetch&lt;/code&gt; for third-party APIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend — &lt;code&gt;backend/formSubmit.jsw&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wix-fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SUBMIT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-backend.example/submit/your-form-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;submitForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SUBMIT_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({}));&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Submission failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Page code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;submitForm&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;backend/formSubmit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onReady&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#submitBtn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;submitForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#nameInput&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#emailInput&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#messageInput&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wix-velo-contact&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nf"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#successBox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;$w&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#errorBox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you also keep a native Wix Form element, pick &lt;strong&gt;one&lt;/strong&gt; primary storage destination. Duplicating to Wix Inbox and an external backend unless you have a clear reason creates sync headaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File uploads in Velo:&lt;/strong&gt; Read the file in page code, encode as &lt;code&gt;data:mime/type;base64,...&lt;/code&gt;, and include it in the JSON body — or use the HTML embed path for simpler multipart uploads.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 4: Automation platforms (Zapier, Make, n8n)
&lt;/h2&gt;

&lt;p&gt;Connect Wix to the rest of your stack without writing a backend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Wix Form submitted&lt;/strong&gt; → &lt;strong&gt;Google Sheets&lt;/strong&gt; (row per submission)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook&lt;/strong&gt; → &lt;strong&gt;Airtable&lt;/strong&gt;, &lt;strong&gt;Notion&lt;/strong&gt;, &lt;strong&gt;HubSpot&lt;/strong&gt;, &lt;strong&gt;Slack&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This works well when non-developers own the workflow. Trade-offs: per-task pricing, another system to maintain, and field mapping that can break if you rename Wix form fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organizing tip:&lt;/strong&gt; One spreadsheet tab (or Airtable base) per form type, with a &lt;code&gt;submitted_at&lt;/code&gt; column added by the automation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 5: Dedicated form backend services
&lt;/h2&gt;

&lt;p&gt;When you want storage, email alerts, and exports without running servers, &lt;strong&gt;form backend services&lt;/strong&gt; are a convenient middle ground between a spreadsheet and a custom API.&lt;/p&gt;

&lt;p&gt;They typically give you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A unique &lt;strong&gt;submit URL&lt;/strong&gt; per form&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;dashboard&lt;/strong&gt; with searchable submissions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email notifications&lt;/strong&gt; on new entries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSV export&lt;/strong&gt; and optional webhooks&lt;/li&gt;
&lt;li&gt;Support for HTML &lt;code&gt;POST&lt;/code&gt;, JSON, and sometimes file attachments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://formcare.io" rel="noopener noreferrer"&gt;FormCare&lt;/a&gt; — one convenient option
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://formcare.io" rel="noopener noreferrer"&gt;FormCare&lt;/a&gt; is built for exactly this use case: you keep designing in Wix (or anywhere else) and point submissions at a FormCare endpoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick setup (~2 minutes):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://formcare.io/register" rel="noopener noreferrer"&gt;Create a free account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Add an &lt;strong&gt;endpoint&lt;/strong&gt; named after your Wix form (e.g. &lt;code&gt;Wix – Contact&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Copy your submit URL: &lt;code&gt;https://formcare.io/api/submit/your-endpoint-id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Connect Wix using any of the methods above:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automations&lt;/strong&gt; → webhook POST to your FormCare URL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Velo&lt;/strong&gt; → &lt;code&gt;fetch&lt;/code&gt; from a &lt;code&gt;.jsw&lt;/code&gt; module (example in Method 3)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML embed&lt;/strong&gt; → set &lt;code&gt;action&lt;/code&gt; to your FormCare URL&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Submissions appear in the FormCare dashboard within seconds. You can set a &lt;strong&gt;custom redirect URL&lt;/strong&gt; on the endpoint for HTML forms (e.g. your Wix thank-you page). Field names are flexible — FormCare stores whatever keys you send.&lt;/p&gt;

&lt;p&gt;FormCare includes a monthly free submission allowance; no credit card is required to create an endpoint and run tests. For a deeper Wix-specific walkthrough, see the &lt;a href="https://formcare.io/blog/wix-formcare-integration-guide" rel="noopener noreferrer"&gt;FormCare Wix integration guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other services in the same category
&lt;/h3&gt;

&lt;p&gt;Depending on your needs, also evaluate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Formspree&lt;/strong&gt;, &lt;strong&gt;Getform&lt;/strong&gt;, &lt;strong&gt;Basin&lt;/strong&gt; — similar HTML-form-to-inbox models&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Forms embedded&lt;/strong&gt; — free, but less control over design on Wix&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosted&lt;/strong&gt; (Node, serverless) — maximum control, you own retention and compliance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose based on file upload limits, GDPR/data residency, pricing at your volume, and whether you need JSON + HTML on the same endpoint.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 6: Your own backend or database
&lt;/h2&gt;

&lt;p&gt;If you already run infrastructure, a small POST handler may be enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Express-style example&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/contact&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;submissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendNotificationEmail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From Wix, reach this via &lt;strong&gt;Automations webhook&lt;/strong&gt;, &lt;strong&gt;Velo &lt;code&gt;.jsw&lt;/code&gt; fetch&lt;/strong&gt;, or &lt;strong&gt;HTML embed&lt;/strong&gt; — same patterns as above. You own the schema, retention policy, and backups.&lt;/p&gt;




&lt;h2&gt;
  
  
  Compare the approaches
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Coding&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Organization&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wix Inbox / CRM&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Single site, few forms&lt;/td&gt;
&lt;td&gt;In-dashboard, limited export&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wix Automations&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Native forms → Sheets/CRM/webhook&lt;/td&gt;
&lt;td&gt;Depends on target&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML embed&lt;/td&gt;
&lt;td&gt;Minimal HTML&lt;/td&gt;
&lt;td&gt;File uploads, simple POST&lt;/td&gt;
&lt;td&gt;External backend or service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Velo + fetch&lt;/td&gt;
&lt;td&gt;Low–medium&lt;/td&gt;
&lt;td&gt;Custom UI, JSON, no reload&lt;/td&gt;
&lt;td&gt;Your API or form backend&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zapier / Make&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Team-owned workflows&lt;/td&gt;
&lt;td&gt;Spreadsheets, CRMs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Form backend (e.g. &lt;a href="https://formcare.io" rel="noopener noreferrer"&gt;FormCare&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Multi-site, exports, alerts&lt;/td&gt;
&lt;td&gt;Built-in submission dashboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom backend&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Full control, compliance&lt;/td&gt;
&lt;td&gt;Your database&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Organization best practices (any method)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One primary destination&lt;/strong&gt; per form — avoid silent duplicates in inbox + sheet + webhook.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stable field names&lt;/strong&gt; — use &lt;code&gt;snake_case&lt;/code&gt; or &lt;code&gt;kebab-case&lt;/code&gt;; avoid renaming after go-live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add context fields&lt;/strong&gt; — &lt;code&gt;source&lt;/code&gt;, &lt;code&gt;form_name&lt;/code&gt;, &lt;code&gt;page_url&lt;/code&gt;, &lt;code&gt;utm_campaign&lt;/code&gt; as hidden inputs or automation mappings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test on the published site&lt;/strong&gt; — Wix Preview does not always mirror live Automations or embed behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan retention&lt;/strong&gt; — know where data lives, how long you keep it, and how users can request deletion (GDPR/CCPA).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduce spam&lt;/strong&gt; — Wix captcha where available; honeypot fields in HTML embeds; rate limits on custom backends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export regularly&lt;/strong&gt; — even with a good dashboard, periodic CSV backups protect against account or platform changes.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Likely cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nothing arrives&lt;/td&gt;
&lt;td&gt;Unpublished site, wrong URL slug&lt;/td&gt;
&lt;td&gt;Publish Wix; verify submit URL; check Automation history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CORS error in browser console&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;fetch&lt;/code&gt; in page code to third party&lt;/td&gt;
&lt;td&gt;Move request to Velo &lt;code&gt;.jsw&lt;/code&gt; backend module&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wrong columns / missing fields&lt;/td&gt;
&lt;td&gt;Mismatch between Wix labels and payload keys&lt;/td&gt;
&lt;td&gt;Align automation mapping or HTML &lt;code&gt;name&lt;/code&gt; attributes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redirect after submit goes elsewhere&lt;/td&gt;
&lt;td&gt;Default referer-based redirect&lt;/td&gt;
&lt;td&gt;Set an explicit thank-you URL on your form backend endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicate entries&lt;/td&gt;
&lt;td&gt;Form submits to Wix and external backend&lt;/td&gt;
&lt;td&gt;Disable one path; single source of truth&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Which path should you pick?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One contact form, you live in Wix&lt;/strong&gt; → Native form + Inbox or CRM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marketing team wants Google Sheets&lt;/strong&gt; → Wix Automations → Sheets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom layout or file uploads, minimal ops&lt;/strong&gt; → HTML embed → form backend such as &lt;a href="https://formcare.io" rel="noopener noreferrer"&gt;FormCare&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive UX, no full-page reload&lt;/strong&gt; → Velo + backend &lt;code&gt;fetch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance-heavy or existing API&lt;/strong&gt; → Custom backend + Automations webhook.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wix is strong on design and publishing; you do not need to sacrifice structured, organized form data to keep it. Pick one storage model, add metadata fields from day one, and test on the live site before you promote the form.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://formcare.io/blog/wix-formcare-integration-guide" rel="noopener noreferrer"&gt;FormCare Wix integration guide&lt;/a&gt; — Automations, Velo, and HTML embed walkthroughs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://formcare.io/docs" rel="noopener noreferrer"&gt;FormCare documentation&lt;/a&gt; — API, JSON payloads, redirects, file uploads&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.wix.com/en/article/wix-automations-an-overview" rel="noopener noreferrer"&gt;Wix Automations overview&lt;/a&gt; — official docs&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Disclosure: This article mentions &lt;a href="https://formcare.io" rel="noopener noreferrer"&gt;FormCare&lt;/a&gt; as one option among several. The integration patterns (Automations, Velo, HTML embed) apply to any HTTPS endpoint that accepts form or JSON POSTs.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>wix</category>
      <category>forms</category>
      <category>webdev</category>
      <category>nocode</category>
    </item>
    <item>
      <title>Simplify Form Handling in Your Web Projects</title>
      <dc:creator>Alexander Polozhevets</dc:creator>
      <pubDate>Fri, 18 Jul 2025 19:44:27 +0000</pubDate>
      <link>https://dev.to/polozhevets/simplify-form-handling-in-your-web-projects-55hl</link>
      <guid>https://dev.to/polozhevets/simplify-form-handling-in-your-web-projects-55hl</guid>
      <description>&lt;p&gt;In today's digital landscape, where websites serve as the frontline for customer interactions, managing form submissions efficiently is crucial. Whether you're running a web studio creating multiple landing pages, an e-commerce site, or a service-based business, handling user data from contact forms, feedback surveys, or lead generation forms can quickly become overwhelming. This is where tools like &lt;a href="https://formcare.io" rel="noopener noreferrer"&gt;FormCare&lt;/a&gt; come in – a robust, secure, and easy-to-use solution for collecting, storing, and managing form data. In this post, we'll explore why using a dedicated form submission tool is essential for your web business and how FormCare solves common pain points.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Common Challenges of Handling Web Forms Without Proper Tools
&lt;/h2&gt;

&lt;p&gt;Imagine you're a web studio juggling dozens of client projects. Each landing page needs a contact form, and without a centralized system, you're stuck with manual email notifications, scattered data storage, or custom backend setups that eat up development time. Or perhaps you're a solo entrepreneur building multiple marketing funnels – dealing with form data security, spam protection, and data organization becomes a nightmare.&lt;/p&gt;

&lt;p&gt;Here are some key problems businesses face:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manual Data Handling:&lt;/strong&gt; Relying on email for form submissions leads to lost data, inbox clutter, and no easy way to organize or search entries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Risks:&lt;/strong&gt; Storing sensitive user data without proper encryption or access controls exposes you to breaches and compliance issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability Issues:&lt;/strong&gt; As your business grows, managing forms across multiple sites becomes inefficient, with no built-in notifications or analytics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Headaches:&lt;/strong&gt; Setting up custom endpoints for each form requires coding expertise, time, and ongoing maintenance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File Upload Complications:&lt;/strong&gt; Handling file attachments (like resumes or images) often requires complex server configurations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These challenges not only waste time but also hinder growth. According to industry reports, poor data management can lead to up to 30% loss in productivity for web-based businesses. That's why investing in a tool like FormCare is not just convenient – it's a strategic necessity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Scenarios Where FormCare Shines
&lt;/h2&gt;

&lt;p&gt;FormCare is designed for versatility, making it ideal for various web business models. Let's look at some examples:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Web Studios and Agencies
&lt;/h3&gt;

&lt;p&gt;If your agency builds landing pages for clients, integrating forms shouldn't slow you down. With FormCare, you can generate unique endpoints in seconds, plug them into any HTML form, and let clients access their data via a secure dashboard. No more custom backends – just seamless integration that supports multipart/form-data for files and JSON for API calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. E-Commerce and Lead Generation Sites
&lt;/h3&gt;

&lt;p&gt;Running multiple product landing pages? FormCare handles high-volume submissions with ease, including file uploads up to 10MB and email notifications. Redirect users post-submission to thank-you pages, and use the admin panel to monitor stats like total submissions and user engagement.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Freelancers and Small Businesses
&lt;/h3&gt;

&lt;p&gt;For those managing their own sites, FormCare's user-friendly interface means no coding required. Register, create an endpoint, and start collecting data securely in MongoDB with GridFS storage. Plus, with features like JWT authentication and Cloudflare CAPTCHA, your data is protected from bots and unauthorized access.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Any Business with Multiple Web Properties
&lt;/h3&gt;

&lt;p&gt;Whether it's blogs, portfolios, or event sites, FormCare centralizes all form data in one place. View submissions, download files, and get insights – all while ensuring compliance with secure practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seamless Integration for Developers: Code Examples
&lt;/h2&gt;

&lt;p&gt;One of FormCare's strengths is its developer-friendly integration. Here's how easy it is to set up:&lt;/p&gt;

&lt;h3&gt;
  
  
  HTML Form Integration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://formcare.io/api/submit/your-endpoint-slug"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt; &lt;span class="na"&gt;enctype=&lt;/span&gt;&lt;span class="s"&gt;"multipart/form-data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Your Name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Your Email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"resume"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JavaScript (AJAX) Integration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;submitForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://formcare.io/api/submit/your-endpoint-slug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With support for JSON and base64 file encoding, it's perfect for modern web apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Choose FormCare Over Building Your Own Solution?
&lt;/h2&gt;

&lt;p&gt;Developing an in-house form handler might seem cost-effective, but it often leads to higher long-term costs due to maintenance, security updates, and scaling challenges. FormCare is already live in production, battle-tested, and continuously improved. With features like automatic backups, CI/CD deployment, and comprehensive API documentation, it offers enterprise-level reliability at an accessible price.&lt;/p&gt;

&lt;p&gt;Plus, in an era where data privacy is paramount, FormCare's compliance with GDPR ensures you're protected against common vulnerabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take Action: Transform Your Web Form Management Today
&lt;/h2&gt;

&lt;p&gt;If you're tired of inefficient form handling holding back your web business, it's time to try FormCare. Whether you're creating landing pages, running a studio, or scaling your online presence, this tool will streamline your processes and let you focus on what matters – growing your business.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://formcare.io" rel="noopener noreferrer"&gt;Sign up now at formcare.io&lt;/a&gt; and experience the difference. Your first endpoint is just minutes away!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>tools</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Are Browser AI Agents a Security Time Bomb? Unpacking the Risks and How to Stay Safe</title>
      <dc:creator>Alexander Polozhevets</dc:creator>
      <pubDate>Sat, 05 Jul 2025 20:33:39 +0000</pubDate>
      <link>https://dev.to/polozhevets/are-browser-ai-agents-a-security-time-bomb-unpacking-the-risks-and-how-to-stay-safe-55fi</link>
      <guid>https://dev.to/polozhevets/are-browser-ai-agents-a-security-time-bomb-unpacking-the-risks-and-how-to-stay-safe-55fi</guid>
      <description>&lt;p&gt;Browser AI agents are the tech world's latest obsession. They promise a future where your browser becomes a proactive assistant, capable of automating everything from booking flights and managing your inbox to conducting complex research. Companies like OpenAI are rolling out agents like Operator, and open-source frameworks like &lt;code&gt;Browser Use&lt;/code&gt; have attracted millions in funding, signaling a major shift in how we interact with the web.&lt;/p&gt;

&lt;p&gt;But as we rush to delegate our digital lives to these powerful new tools, we're overlooking a critical question: Are they secure?&lt;/p&gt;

&lt;p&gt;Recent research suggests that while we're dreaming of productivity gains, we might be creating a security nightmare. This post dives into the hidden dangers of browser AI agents and outlines the crucial steps we need to take to stay safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Problem: An Accomplice with Your Password
&lt;/h2&gt;

&lt;p&gt;The fundamental security risk of a browser agent lies in a simple fact: &lt;strong&gt;it operates with your identity and privileges, but without your security awareness.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An employee can be trained to spot a phishing email. They might hesitate before clicking a suspicious link or granting a random application access to their Google account. An AI agent, in its current form, does not. As a recent report from security firm SquareX noted, agents have effectively "dethroned employees as the weakest link within organizations."&lt;/p&gt;

&lt;p&gt;When an agent browses the web for you, it uses your cookies, your logged-in sessions, and potentially your saved credentials. If an attacker can trick that agent, they aren't just compromising a piece of software; they're compromising &lt;em&gt;you&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Workplace: A Magnified Threat
&lt;/h2&gt;

&lt;p&gt;The stakes get even higher when these agents enter the workplace. Imagine an agent that has access not just to your personal email, but to your company's Salesforce instance, your private GitHub repositories, or the internal financial reporting system.&lt;/p&gt;

&lt;p&gt;In a corporate environment, agents operate with the permissions of a trusted employee. A successful attack is no longer about stealing an individual's password; it's about gaining a foothold into a corporate network. A single hijacked agent could potentially:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Exfiltrate customer data from a CRM.&lt;/li&gt;
&lt;li&gt;  Leak proprietary source code.&lt;/li&gt;
&lt;li&gt;  Initiate fraudulent financial transactions.&lt;/li&gt;
&lt;li&gt;  Deploy malware inside the company's firewall.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent becomes a highly privileged insider threat that doesn't even know it's malicious. This turns a single employee's lapse in judgment into a potential enterprise-wide security incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Top 5 Security Risks of Browser AI Agents
&lt;/h2&gt;

&lt;p&gt;Let's break down the specific, research-backed ways these agents can be exploited.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Prompt Injection &amp;amp; Task Hijacking
&lt;/h3&gt;

&lt;p&gt;This is the most direct way to attack an agent. An attacker embeds malicious instructions within the content of a webpage—it could be in a product review, a forum comment, or even a hidden &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; tag. When the agent parses this content to understand the page, it unintentionally executes the attacker's commands.&lt;/p&gt;

&lt;p&gt;A recent paper, "The Hidden Dangers of Browsing AI Agents," demonstrated this by forcing an agent to leak a user's credentials simply by having it read a malicious GitHub issue page.&lt;/p&gt;

&lt;p&gt;A more subtle version of this is the "task-aligned injection," where malicious commands are framed as helpful guidance. The agent, trying to complete its task, is steered into performing actions it shouldn't, like navigating to a malicious website or divulging sensitive information.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. OAuth and Phishing Scams 2.0
&lt;/h3&gt;

&lt;p&gt;We're all familiar with fake login pages. But what happens when your AI assistant can't tell the difference?&lt;/p&gt;

&lt;p&gt;Security researchers at SquareX demonstrated a scenario where an agent was tasked with finding a file-sharing tool. The agent was directed to a malicious site and initiated an OAuth flow to "register." It blindly approved the permissions, granting the attacker's application full access to the user's email account, despite clear warning signs like irrelevant permission requests and suspicious URLs.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Credential &amp;amp; Data Exfiltration
&lt;/h3&gt;

&lt;p&gt;Because agents operate within your browser, they have access to a treasure trove of sensitive data. A hijacked agent can be instructed to find and exfiltrate session cookies, local storage data, or even autofill passwords.&lt;/p&gt;

&lt;p&gt;The popular open-source framework &lt;code&gt;Browser Use&lt;/code&gt; was recently assigned a CVE after researchers discovered a vulnerability that allowed for exactly this kind of credential exfiltration. The agent could be tricked into revealing sensitive information, leading to the compromise of user accounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Context &amp;amp; Memory Manipulation
&lt;/h3&gt;

&lt;p&gt;To perform multi-step tasks, agents need to remember what they've done. This "memory" or "context" is their internal representation of the task. A new attack vector, detailed in the paper "Context manipulation attacks," is to corrupt this memory directly.&lt;/p&gt;

&lt;p&gt;This is called a "plan injection" attack. By poisoning the agent's memory, an attacker can fundamentally alter its understanding of the task, making it up to &lt;strong&gt;3 times more effective&lt;/strong&gt; than traditional prompt injection. The agent isn't just tricked into a wrong turn; its entire map is redrawn by the attacker.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Domain and URL Validation Bypass
&lt;/h3&gt;

&lt;p&gt;Most security-conscious agents have an "allowlist" of trusted domains they can visit. But even this can be bypassed. &lt;br&gt;
Researchers found that the validation logic in &lt;code&gt;Browser Use&lt;/code&gt; could be fooled with a specially crafted URL:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://example.com:pass@malicious-site.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The agent's parser would see &lt;code&gt;example.com&lt;/code&gt;, assume the URL was safe, but the browser would actually navigate to &lt;code&gt;malicious-site.com&lt;/code&gt;. This simple trick completely undermines one of the agent's core security features.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Protect Yourself: A Guide for Users and Developers
&lt;/h2&gt;

&lt;p&gt;The situation isn't hopeless, but it requires a shift in mindset. We need to treat these agents with caution and build them with security as a foundational layer, not an afterthought.&lt;/p&gt;

&lt;h3&gt;
  
  
  For Users
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Choose Wisely&lt;/strong&gt;: Stick to reputable agents from trusted developers like OpenAI, Google, or Anthropic. Be extremely wary of installing unknown AI-powered browser extensions.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Use a Dedicated Browser Profile&lt;/strong&gt;: Don't run an AI agent in the same browser profile as your primary work or personal accounts. Create a separate, sandboxed profile for it with its own set of logins.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Mind the Permissions&lt;/strong&gt;: When you install an agent, review the permissions it requests. Does it really need access to everything?&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Stay Skeptical&lt;/strong&gt;: Monitor your agent's actions. If it starts behaving weirdly, shut it down. Don't trust it with highly sensitive tasks just yet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  For Developers Building Agents
&lt;/h3&gt;

&lt;p&gt;The dev.to audience is at the forefront of this technology, and we have a responsibility to build it securely.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Assume Zero Trust&lt;/strong&gt;: Treat all web content—every piece of HTML, every user comment—as potentially malicious. Sanitize all inputs vigorously before they get anywhere near the agent's core logic.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Isolate the Planner from the Executor&lt;/strong&gt;: A key architectural pattern is to separate the agent's "brain" (the planner LLM) from its "hands" (the executor that performs actions). The planner should never process raw, untrusted web content. It should only see a sanitized, structured representation of the state.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Require Human-in-the-Loop&lt;/strong&gt;: For any sensitive action—entering credentials, submitting a form with PII, authorizing a payment—the agent must stop and get explicit confirmation from the human user.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Implement Robust Guardrails&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  Use strict domain allowlists with a secure, battle-tested URL parser.&lt;/li&gt;
&lt;li&gt;  Implement rate limiting to prevent an agent from going haywire.&lt;/li&gt;
&lt;li&gt;  Monitor for anomalous behavior, like an agent suddenly trying to access local files or send large amounts of data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Secure the Memory&lt;/strong&gt;: The agent's context is a primary target. Protect it from tampering and ensure that a malicious website can't poison its understanding of its task.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion: Taming the Agent
&lt;/h2&gt;

&lt;p&gt;Browser AI agents are an incredibly exciting technology with the potential to change how we work and live online. However, the industry is accumulating a significant "security debt," as one paper aptly put it. We are shipping features faster than we are building safeguards.&lt;/p&gt;

&lt;p&gt;The path forward requires a dual approach: users must remain cautious and vigilant, and developers must embrace a security-first mindset. If we don't, we risk turning our powerful new assistants into the most effective security threat we've ever willingly installed on our own machines. &lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>webdev</category>
      <category>privacy</category>
    </item>
    <item>
      <title>React.js and SEO: How to Make Google Love Your Single Page App</title>
      <dc:creator>Alexander Polozhevets</dc:creator>
      <pubDate>Fri, 04 Jul 2025 09:03:20 +0000</pubDate>
      <link>https://dev.to/polozhevets/reactjs-and-seo-how-to-make-google-love-your-single-page-app-582n</link>
      <guid>https://dev.to/polozhevets/reactjs-and-seo-how-to-make-google-love-your-single-page-app-582n</guid>
      <description>&lt;p&gt;React is a fantastic library for building fast, interactive, and modern user interfaces. But if you've ever built a single-page application (SPA) with it, you might have heard whispers of a scary monster lurking in the shadows: &lt;strong&gt;bad SEO&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The fear is real. You've built a beautiful, dynamic application, but when it comes to search engine rankings, you're nowhere to be found. Why? And more importantly, how do you fix it?&lt;/p&gt;

&lt;p&gt;This post is your problem-solving guide to navigating the world of React and SEO. We'll break down why SPAs and search engines don't always get along and explore practical solutions to make your React app an SEO powerhouse.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Problem: The Empty HTML File
&lt;/h2&gt;

&lt;p&gt;Imagine you invite a friend to a new apartment you're furnishing. They arrive, but the delivery truck with all your furniture is stuck in traffic. All they see is an empty space. They know furniture is &lt;em&gt;coming&lt;/em&gt;, but they can't see it &lt;em&gt;yet&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This is often what happens when a search engine crawler like Googlebot visits a typical client-side rendered (CSR) React app. The server sends a very basic HTML file, often with just a single &lt;code&gt;&amp;lt;div id="root"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; and a large JavaScript bundle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My Awesome React App&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/static/js/bundle.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The crawler sees an almost empty page. All the rich content, the text, the images—it's all supposed to be rendered by that JavaScript file. While Googlebot has gotten much better at executing JavaScript, it's not perfect. It can be slow, it might miss things, and other search engines might not be as advanced.&lt;/p&gt;

&lt;p&gt;This is the central problem of &lt;strong&gt;React SEO&lt;/strong&gt;: we need to deliver a fully "furnished" HTML page to search engine crawlers, not an empty one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving the Problem: The Modern React SEO Toolkit
&lt;/h2&gt;

&lt;p&gt;Luckily, the React ecosystem has evolved, and we now have powerful tools to solve this issue. Here are the most effective solutions.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Server-Side Rendering (SSR) with Next.js
&lt;/h3&gt;

&lt;p&gt;Server-Side Rendering is the most robust solution to the React SEO problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is it?&lt;/strong&gt; Instead of sending an empty HTML file, the server renders the React components into a full HTML page &lt;em&gt;before&lt;/em&gt; sending it to the browser (or the crawler). The user gets a complete page immediately, and so does the search engine bot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is it great for SEO?&lt;/strong&gt; Crawlers get a fully-rendered, content-rich HTML page on the first request. It's the SEO equivalent of a perfectly furnished apartment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to do it?&lt;/strong&gt; The most popular way to implement SSR in React is with &lt;strong&gt;Next.js&lt;/strong&gt;. It's a framework that makes server-rendering, routing, and other production-grade features straightforward.&lt;/p&gt;

&lt;p&gt;Here's a simple example of a Next.js page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pages/index.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;HomePage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;My&lt;/span&gt; &lt;span class="nx"&gt;Blog&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This function runs on the server for every request&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getServerSideProps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Fetch data from an external API&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.example.com/posts`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Pass data to the page via props&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;HomePage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;getServerSideProps&lt;/code&gt; fetches the blog posts on the server. The &lt;code&gt;HomePage&lt;/code&gt; component is rendered to HTML with that data and sent to the client.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Static Site Generation (SSG) with Gatsby or Next.js
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What is it?&lt;/strong&gt; SSG is similar to SSR, but it happens at &lt;em&gt;build time&lt;/em&gt;. The entire website is pre-rendered into static HTML files. When a user requests a page, they are just served a plain old HTML file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When is it useful?&lt;/strong&gt; This is perfect for sites where the content doesn't change on every request, like blogs, marketing sites, portfolios, and documentation. It's incredibly fast and fantastic for SEO.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to do it?&lt;/strong&gt; &lt;strong&gt;Gatsby&lt;/strong&gt; is a powerful static site generator built on React. &lt;strong&gt;Next.js&lt;/strong&gt; also has excellent SSG capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Manage Your  with React Helmet Async
&lt;/h3&gt;

&lt;p&gt;Whether you're using SSR, SSG, or even just a standard client-side React app, you need to manage your page's &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag. This is where crucial SEO information like the page title and meta description lives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; In a standard React SPA, you have one &lt;code&gt;index.html&lt;/code&gt; file, so you have one &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;. As the user navigates your app, the title doesn't change, which is bad for both user experience and SEO.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt; Use a library like &lt;code&gt;react-helmet-async&lt;/code&gt;. It allows you to manage the document head from within your components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;react-helmet&lt;/code&gt; vs. &lt;code&gt;react-helmet-async&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You might see tutorials mentioning &lt;code&gt;react-helmet&lt;/code&gt;. While it was the original standard, it is no longer actively maintained and is not recommended for modern server-side rendering setups. &lt;code&gt;react-helmet&lt;/code&gt; has issues with thread safety which can cause memory leaks on the server.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;react-helmet-async&lt;/code&gt; was created to solve this problem. It's designed to work safely in asynchronous environments like server-side rendering with Node.js, making it the clear choice for any new project, especially if you're using Next.js or a similar framework.&lt;/p&gt;

&lt;p&gt;To use it, you first need to wrap your application in a &lt;code&gt;HelmetProvider&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In your _app.js or main entry file&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HelmetProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-helmet-async&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HelmetProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/HelmetProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you can use the &lt;code&gt;Helmet&lt;/code&gt; component in any page or component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In a page component like pages/about.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Helmet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-helmet-async&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;AboutPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Helmet&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;About&lt;/span&gt; &lt;span class="nx"&gt;Us&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;My&lt;/span&gt; &lt;span class="nx"&gt;Awesome&lt;/span&gt; &lt;span class="nx"&gt;Company&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/title&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Learn more about our mission and our team.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;canonical&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.my-awesome-company.com/about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Helmet&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;About&lt;/span&gt; &lt;span class="nx"&gt;Us&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;about&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when a user navigates to the "About" page, the title, description, and even canonical links will be updated dynamically. When used with SSR, this information is rendered on the server, so crawlers see a unique, descriptive head for every page.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Crafting an SEO-Friendly &lt;code&gt;index.html&lt;/code&gt; for Vite SSG
&lt;/h3&gt;

&lt;p&gt;While frameworks like Next.js handle much of the HTML generation for you, you might be using a tool like &lt;strong&gt;Vite&lt;/strong&gt; to build a static React site. In this case, your &lt;code&gt;index.html&lt;/code&gt; file at the root of your project is your SEO foundation. Getting it right is crucial.&lt;/p&gt;

&lt;p&gt;Here's how to structure your &lt;code&gt;index.html&lt;/code&gt; for best SEO practices right out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Anatomy of an SEO-Optimized &lt;code&gt;index.html&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;index.html&lt;/code&gt; should contain robust default metadata. While libraries like &lt;code&gt;react-helmet-async&lt;/code&gt; will override these values on a per-page basis, these defaults are important for your homepage and as a fallback.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Primary Meta Tags --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;My Awesome Vite React App | Homepage&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A brief but compelling description of your website."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"keywords"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"react, vite, seo, javascript, web development"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Open Graph / Facebook --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://www.yourdomain.com/"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"My Awesome Vite React App | Homepage"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A brief but compelling description of your website."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://www.yourdomain.com/og-image.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Twitter --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"twitter:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://www.yourdomain.com/"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"My Awesome Vite React App | Homepage"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A brief but compelling description of your website."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://www.yourdomain.com/twitter-image.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/svg+xml"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.svg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://www.yourdomain.com/"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Noscript Fallback --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Welcome to My Awesome Vite React App&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This site requires JavaScript to be enabled to function properly. Please enable JavaScript in your browser settings to continue.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;You can find more information about our services on our main page.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/src/main.jsx"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why the &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; Tag Matters for SEO&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; tag is a simple but powerful tool. It provides content that will be displayed by browsers that have JavaScript disabled. While Google's crawler is very good at executing JavaScript, it's not perfect, and other crawlers may not be as capable.&lt;/p&gt;

&lt;p&gt;Including a &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; tag provides a fallback that ensures there's &lt;em&gt;always&lt;/em&gt; some indexable content on the page, which is a solid SEO best practice.&lt;/p&gt;

&lt;p&gt;This well-structured &lt;code&gt;index.html&lt;/code&gt; provides a strong SEO starting point. From here, you can use &lt;code&gt;react-helmet-async&lt;/code&gt; within your React components to customize the metadata for each page of your application, creating a highly optimized static site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus SEO Tips for React
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semantic HTML:&lt;/strong&gt; Use &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, etc. correctly. It helps crawlers understand your content structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meaningful URLs:&lt;/strong&gt; Use a library like &lt;strong&gt;React Router&lt;/strong&gt; to create clean, descriptive URLs (e.g., &lt;code&gt;/products/react-seo-guide&lt;/code&gt; instead of &lt;code&gt;/product?id=123&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image &lt;code&gt;alt&lt;/code&gt; attributes:&lt;/strong&gt; Always provide descriptive &lt;code&gt;alt&lt;/code&gt; text for your images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Sitemap:&lt;/strong&gt; For frameworks like Next.js, you can automate sitemap generation. Install a package like &lt;code&gt;next-sitemap&lt;/code&gt; and add a post-build script. This will create an up-to-date &lt;code&gt;sitemap.xml&lt;/code&gt; file every time you build your site. A sitemap is crucial for telling search engines about all the pages on your site you want them to crawl.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure &lt;code&gt;robots.txt&lt;/code&gt;:&lt;/strong&gt; This file, placed in your public directory, tells search engine crawlers which pages or files they can or cannot request from your site. A good starting point for a Next.js app is:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  User-agent: *
  Allow: /

  Sitemap: https://www.yourdomain.com/sitemap.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows all crawlers to access all pages and points them to your sitemap. You might disallow specific paths, like &lt;code&gt;/api/&lt;/code&gt; routes if you don't want them crawled.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structured Data (Schema Markup):&lt;/strong&gt; Add JSON-LD structured data to your pages to help Google understand your content even better and give you rich snippets in search results.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion: React and SEO Can Be Best Friends
&lt;/h2&gt;

&lt;p&gt;The myth that React is bad for SEO is a thing of the past. While a basic client-side rendered React app can present challenges, the modern React ecosystem provides all the tools you need to build highly-optimized, search-engine-friendly websites.&lt;/p&gt;

&lt;p&gt;By choosing the right rendering strategy for your project—be it SSR or SSG with a framework like &lt;strong&gt;Next.js&lt;/strong&gt;—and by paying attention to SEO fundamentals like metadata management with &lt;strong&gt;React Helmet&lt;/strong&gt;, you can have the best of both worlds: a world-class user experience and top-notch SEO performance.&lt;/p&gt;




&lt;p&gt;If this guide helped you, consider &lt;a href="https://buymeacoffee.com/polozhevets" rel="noopener noreferrer"&gt;buying me a coffee&lt;/a&gt; ☕️&lt;/p&gt;

</description>
      <category>reacts</category>
      <category>javascript</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Migrate from Create-React-App to Vite</title>
      <dc:creator>Alexander Polozhevets</dc:creator>
      <pubDate>Thu, 03 Jul 2025 10:32:58 +0000</pubDate>
      <link>https://dev.to/polozhevets/migrate-from-create-react-app-to-vite-77n</link>
      <guid>https://dev.to/polozhevets/migrate-from-create-react-app-to-vite-77n</guid>
      <description>&lt;h2&gt;
  
  
  From Create React App to Vite: The Why and How
&lt;/h2&gt;

&lt;p&gt;If you've been in the React ecosystem for a while, you're probably familiar with Create React App (CRA). For years, it was the go-to tool for bootstrapping new React projects. But the web moves fast, and today, there's a new champion of developer experience: &lt;strong&gt;Vite&lt;/strong&gt; (pronounced "veet").&lt;/p&gt;

&lt;p&gt;CRA is no longer actively maintained, and even the React team recommends other tools. If you're still using CRA, you're missing out on a faster, more modern development workflow.&lt;/p&gt;

&lt;p&gt;This guide will walk you through why you should migrate and how to do it in the most painless way possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Ditch Create React App?
&lt;/h3&gt;

&lt;p&gt;The difference is night and day. Here's why you'll love Vite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Blazing Speeds:&lt;/strong&gt; Vite's dev server is built on native ES modules (ESM), which means it serves your code directly to the browser without a slow, heavy bundling step. This results in &lt;strong&gt;near-instant server start-up&lt;/strong&gt; and &lt;strong&gt;lightning-fast Hot Module Replacement (HMR)&lt;/strong&gt;. No more waiting minutes for your project to load!&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;A Better Developer Experience:&lt;/strong&gt; Say goodbye to the "black box" of &lt;code&gt;react-scripts&lt;/code&gt;. Vite's configuration is simple, transparent, and easy to extend. You get out-of-the-box support for modern features like TypeScript, JSX, and CSS pre-processors without the headache.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;It's the Future:&lt;/strong&gt; The ecosystem is rapidly moving towards modern, ESM-based tooling. Vite is at the forefront of this shift, and its popularity is soaring.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Level Up Your Package Manager: Why You Should Use pnpm
&lt;/h3&gt;

&lt;p&gt;While you're upgrading your build tool, you should also consider your package manager. If you're coming from CRA, you're likely using &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;yarn&lt;/code&gt;. It's time to switch to &lt;strong&gt;pnpm&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why pnpm?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Massive Disk Space Savings:&lt;/strong&gt; &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt; duplicate packages across your projects. &lt;code&gt;pnpm&lt;/code&gt; uses a single, global content-addressable store and links files to your projects. This means you'll only ever have one copy of a package version on your disk, saving gigabytes of space.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Blazing-Fast Installs:&lt;/strong&gt; Thanks to its efficient linking strategy, &lt;code&gt;pnpm&lt;/code&gt; is significantly faster than its counterparts, especially when installing packages you've used before.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;No More Phantom Dependencies:&lt;/strong&gt; &lt;code&gt;pnpm&lt;/code&gt;'s strict &lt;code&gt;node_modules&lt;/code&gt; layout means your code can't access packages you haven't explicitly declared in your &lt;code&gt;package.json&lt;/code&gt;. This prevents a whole class of bugs and makes your projects more reliable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;A Quick Comparison:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;npm / Yarn Classic&lt;/th&gt;
&lt;th&gt;pnpm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Slow to Medium&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fast&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Disk Space&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High (duplicates)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Efficient (linking)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;node_modules&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Flat (allows phantom deps)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strict (no phantom deps)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To get started, install it globally: &lt;code&gt;npm install -g pnpm&lt;/code&gt;. Then, simply use &lt;code&gt;pnpm&lt;/code&gt; commands (&lt;code&gt;pnpm install&lt;/code&gt;, &lt;code&gt;pnpm add&lt;/code&gt;, etc.) instead of &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;yarn&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Migrate: A Simple, Step-by-Step Guide
&lt;/h3&gt;

&lt;p&gt;Migrating doesn't have to be a week-long ordeal. For most projects, you can get it done in under an hour. Here's the simplest way to do it:&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Create a New Vite Project
&lt;/h4&gt;

&lt;p&gt;To ensure a clean setup, we'll start a new Vite project from scratch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm create vite your-new-app &lt;span class="nt"&gt;--template&lt;/span&gt; react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Move Your Source Files
&lt;/h4&gt;

&lt;p&gt;Copy your &lt;code&gt;src&lt;/code&gt; folder from your old CRA project directly into your new Vite project, replacing the existing &lt;code&gt;src&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;If you have assets (like images or fonts) in your CRA &lt;code&gt;public&lt;/code&gt; folder, move them into the &lt;code&gt;public&lt;/code&gt; folder in your new Vite project.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Update Your Dependencies
&lt;/h4&gt;

&lt;p&gt;Open the &lt;code&gt;package.json&lt;/code&gt; from your old project and copy your &lt;code&gt;dependencies&lt;/code&gt; over to the new &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Do &lt;strong&gt;not&lt;/strong&gt; copy &lt;code&gt;react-scripts&lt;/code&gt;. This is a CRA-specific package that you no longer need.&lt;/p&gt;

&lt;p&gt;Now, install the dependencies in your new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4: Adjust Your &lt;code&gt;index.html&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This is a key difference. CRA keeps &lt;code&gt;index.html&lt;/code&gt; in the &lt;code&gt;public&lt;/code&gt; folder, while Vite keeps it in the root.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;index.html&lt;/code&gt; in your new project and make sure the script tag points to your main entry file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- index.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/src/index.jsx"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice there's no need for &lt;code&gt;%PUBLIC_URL%&lt;/code&gt; anymore. It just works.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 5: Update Environment Variables
&lt;/h4&gt;

&lt;p&gt;If you use environment variables, you'll need to change the prefix from &lt;code&gt;REACT_APP_&lt;/code&gt; to &lt;code&gt;VITE_&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;REACT_APP_API_KEY&lt;/code&gt; becomes &lt;code&gt;VITE_API_KEY&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You'll also need to update how you access them in your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before (CRA)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REACT_APP_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// After (Vite)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Common Gotchas (and Easy Fixes)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;JSX in &lt;code&gt;.js&lt;/code&gt; files:&lt;/strong&gt; Vite is stricter than CRA. If you're using JSX, your file needs a &lt;code&gt;.jsx&lt;/code&gt; or &lt;code&gt;.tsx&lt;/code&gt; extension. A quick rename is all you need.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Path Aliases:&lt;/strong&gt; If you want cleaner imports (e.g., &lt;code&gt;import Component from '@/components/MyComponent'&lt;/code&gt;), you can set up path aliases in your &lt;code&gt;vite.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SVGs as Components:&lt;/strong&gt; If you were importing SVGs as React components in CRA, you'll need a plugin for Vite. &lt;code&gt;vite-plugin-svgr&lt;/code&gt; is a great choice.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Migrating from Create React App to Vite is one of the highest-leverage changes you can make to improve your development workflow. You'll get a faster, more modern toolchain that will make you a more productive and happier developer.&lt;/p&gt;

&lt;p&gt;When you do this with one project, you'll want to migrate your entire legacy! Take your time :)&lt;/p&gt;




&lt;p&gt;If this guide helped you, consider &lt;a href="https://buymeacoffee.com/polozhevets" rel="noopener noreferrer"&gt;buying me a coffee&lt;/a&gt; ☕️&lt;/p&gt;

</description>
      <category>react</category>
      <category>vite</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I was tired of writing backend code for every contact form</title>
      <dc:creator>Alexander Polozhevets</dc:creator>
      <pubDate>Wed, 02 Jul 2025 19:22:50 +0000</pubDate>
      <link>https://dev.to/polozhevets/i-was-tired-of-writing-backend-code-for-every-contact-form-345</link>
      <guid>https://dev.to/polozhevets/i-was-tired-of-writing-backend-code-for-every-contact-form-345</guid>
      <description>&lt;p&gt;I have a confession. For the longest time, whenever a simple project needed a contact form, I'd just use a &lt;code&gt;mailto:&lt;/code&gt; link and call it a day, because I couldn't be bothered to set up a whole backend just for that.&lt;/p&gt;

&lt;p&gt;When I did it "properly," it always felt like a chore. Writing a serverless function meant boilerplate. Pulling in a full BaaS felt like bringing a cannon to a knife fight.&lt;/p&gt;

&lt;p&gt;So, I finally built a little utility for myself to solve this: &lt;strong&gt;&lt;a href="https://formcare.io" rel="noopener noreferrer"&gt;formcare.io&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's basically just an endpoint that you can point any existing HTML form to.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt; Sign up and create a new endpoint.&lt;/li&gt;
&lt;li&gt; It gives you a unique URL.&lt;/li&gt;
&lt;li&gt; You stick that URL in your &lt;code&gt;&amp;lt;form action="..."&amp;gt;&lt;/code&gt; attribute. Done.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; 
  &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://formcare.io/api/submit/your-unique-slug"&lt;/span&gt; 
  &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt; 
  &lt;span class="na"&gt;enctype=&lt;/span&gt;&lt;span class="s"&gt;"multipart/form-data"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Your Name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Your Email"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"attachment"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Send&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It handles &lt;code&gt;multipart/form-data&lt;/code&gt; (so file uploads work out of the box) and also &lt;code&gt;application/json&lt;/code&gt; for JS-heavy sites. The submissions just show up in a simple dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  I'd love your feedback
&lt;/h3&gt;

&lt;p&gt;I'm posting this here because I'm genuinely not sure if this is just a 'me' problem or if other devs find this as annoying as I do. I'd love for you to take a look and tell me what you think.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it solving a real problem? Is something totally broken? Did I just reinvent the wheel for the 1000th time?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Maybe it helps someone save some time at least. Thanks to everyone who reads this.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>productivity</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
