[Support Guide] Netlify forms with custom success pages for Gatsby and Nuxt

It’s a common design pattern to route visitors to a new page when they successfully submit a form. But figuring out how to get that route working can be tricky. Do you need a _redirects file? (Spoiler alert: no.) Are your form attributes set up correctly to work with Netlify? When you’re deciding which routing functions to use, do you start at the framework (React, Vue) level, the static site generator (Gatsby, Nuxt) level, or somewhere else?

This post links to examples of custom success pages with two popular static site generators: Gatsby (React) and Nuxt (Vue). You’ll see that many of the elements of these forms are exactly the same! And once you get the hang of the similarities, we hope it’ll become easier to understand the differences and apply what you learn to other frameworks that we don’t cover here. There’s also a separate post all about Netlify forms that I highly recommend checking out: [Support Guide] Form problems, form debugging, 404 when submitting and keep in mind that what follows are just a few ways to do forms on Netlify. There are certainly other ways, and we’d love to hear how else you’re doing custom success pages.

Sample code

If you want to cut to the chase, the code is here and both examples include comments that link out to additional references:

Note that these are bare bones examples of forms that only accept text—not files—so they use the "Content-Type": "application/x-www-form-urlencoded" HTTP request header. This is why they both require a URL encoding function, explained below. These examples don’t implement fancy things like file submissions or reCAPTCHA; the idea was to focus mainly on the custom success page.

Putting the pieces together

At a high level, the pieces you need in order to submit text and then route to a custom success page, regardless of what framework you’re using, are:

  • The form body
  • The POST request
  • The route to the success page
  • The success page itself

The form body

  • This is covered extensively in the support guide linked above and in our docs.

The POST request

  • You need to send specific Content-Type headers that differ depending on what kind of content users are submitting in your form. These are described in the [Common Issue] above.
  • You need to encode the form! This snags many a Netlify form builder. In the examples above, you’ll see two slightly different encoding functions that do the same thing: they take in your form data and encode it as a URL.

The route to the success page

  • In both code examples above, you’ll see that the routing step happens in the handleSubmit function and nowhere else.
  • The functions themselves differ by framework and static site generator.
    • With Nuxt, you can use Vue’s this.$router.push
    • With Gatsby, you can use the navigate helper function, which uses the Reach Router library under the hood: Reach Router: Next Generation Routing for React
    • For other stacks, I would start by looking at the docs for the static site generator. You’re looking for programmatic or dynamic routing, and there is usually a concept of “pushing” the new route to your browser’s history. If you don’t find what you need there, it’s time to look to the framework for the idiomatic way to do client-side routing. Remember: if you end up reading docs about server-side routing, stop what you’re doing and slowly back away into the bushes! Netlify (and the JAMStack in general) prerenders your site and serves the site’s static files from a CDN; there is no web server at runtime.

The success page itself

  • In both Gatsby/React and Nuxt/Vue, this lives in /pages alongside your primary “home” page. There are tons of ways to make this page—with or without components, with functional or class components, with or without additional methods or styling. All of that is up to you, but the page itself does need to exist and its name needs to correspond to the route in your handleSubmit function.

There you have it! A few ways to do forms with custom success pages on Netlify. We know there are many other ways, so let us know below how you’re doing custom success pages for your Gatsby/React and Nuxt/Vue forms.

And as always, if you need help troubleshooting, please create a new post, and we’ll do our best to unstick you.


Hi, I’m new on React and I would like to know if is possible to create a Success Page without gastsby?

Because I have already done just a Test form using react, and I just need to connect my success page on it, is there other way or I have to install gatsby?

If I have to is there any way I could just install using “npm install -g gatsby-cli” and go to my form and include import { navigate } from ‘gatsby’ this would work?


i don’t think you should need to introduce the bloat of adding gatsby to your project if you don’t need it, just to show a success page.

Did you see this already?

Hi Perry, thanks for your reply.

So I saw but it didn’t work, see the link below.

I’m using Formik so I had to do changed on the index.html to make it work, but worked the only problem is the Success Page. If you want to see my Component see below.

Thanks so much.

import React from "react"
import {Formik, Form, Field, ErrorMessage} from "formik"
import * as Yup from "yup"

const initialValues = {
    name: '',
    email: '',
    channel: ''

const encode =(data) => {
    return Object.keys(data)
        .map(key => encodeURIComponent(key) + "=" +  encodeURIComponent(data[key]))

const onSubmit = (values, actions) => {
    fetch("/", {
        method: 'POST',
        headers: {"Content-Type": "application/x-www-form-urlencoded"},
        body: encode({
            'form-name': 'contact',
    .then(() => {
    .catch((error) => {
    console.log('Form data_1', values, actions)

const validationSchema = Yup.object({
    name: Yup.string().required("Required!"),
    email: Yup.string().email("Invalid email format").required("Required"),
    channel: Yup.string().required("Required")

function YouTubeForm(props) {
            <Form name="contact" className="form" action="../pages/thankyou/"> 
                <div className="form-control">
                    <label htmlFor="name">Name</label> 
                    <ErrorMessage name="name" />
                <div className="form-control">
                    <label htmlFor="email">Email</label>
                    <ErrorMessage name="email" />
                <div className="form-control">
                    <label htmlFor="channel">Channel</label>
                    <ErrorMessage name="channel" />
                <div data-netlify-recaptcha={true}></div>
                <button type="submit">Submit-2</button>
export default YouTubeForm

hmm, that goes a bit beyond my knowledge, but maybe @jonsully has an idea?

1 Like

Greetings :wave:t2:

@NetoSena you don’t need to use Gatsby to submit a client-side / javascript-driven form. Your component looks great. You just need an extra piece or two. Which static builder are you using to generate your site? Create React App?


Hi Jon, I’m using Create react app.

Great! I don’t think CRA comes with any client-side routing out of the box so you should just be able to add something like

window.location = 'https://example.com/success"

right after the actions.resetForm() line in your onSubmit() handler.


Hi Jon,
Thanks so much for you reply.

So I’m almost there…
Now I’m getting the “Page is not Found” but I have tried on 2 ways:

    • window.location = './thankyou' => it didn’t work
    • window.location = 'https://optimistic-shannon-8bb3e7.netlify.app/thankyou' => it didn’t work.

I’m not sure but have I to import this “Page” called “thankyou.js” such as import thankyou from "thankyou in the Component.

I have tried this above and I was getting error such as

window.location = 'Creating an optimized production build... 7:47:54 PM: Failed to compile. 7:47:54 PM: 7:47:54 PM: ./src/components/YouTubeForms.js 7:47:54 PM: Cannot find file './Thankyou' in './src/components'. 7:47:54 PM: npm ERR! code ELIFECYCLE'

For that reason I have tried to put lowercase on the name of the page “thankyou” before It was “Thankyou” => but didin’t work.

So I don’t know what I’m missing here.


Hey @NetoSena

Can you try window.location = '/thankyou'? without the period


Hi Jon,

Man unfortunetely it didn’t work I have got the same message “page not found”
Have I to call this component one the FormComponent? like a normal link I mean when we use like a “Switch, Route”?