Gatsby + Netlify Form + Recaptcha status 400

Hey all,

So I’ve been having this problem for a few days and I’ve tried every answer I can find to provide a solution and had no luck.

I have a site built in Gatsby. I have a contact form, using axios to submit to netlify. The form works perfectly fine without Recaptcha and I had honeypot on there before but spam was still getting through. So I’ve opted to try and implement Recaptcha (react-google-recaptcha) and I’ve managed to get it to a point where it submits, but not successfully.

A status code of 400 comes back in console. I’ve not had any other errors.

I’ve looked at previous posts and articles all about gatsby + netlify + recaptcha, followed so closely and I’m getting nowhere with it.

I’ve got the environment variables set up in Netlify as follows;

  • GATSBY_SITE_RECAPTCHA_KEY
  • SITE_RECAPTCHA_KEY
  • SITE_RECAPTCHA_SECRET (although I don’t understand how/where this is used)

Please see the code below. Fingers crossed someone can spot something. I’m currently at a loss.

// Imports
// ------------
import React, { useRef, useState, useEffect } from 'react';
import Input from '@parts/Input';
import Button from '@parts/Button';
import axios from 'axios';
import ReCAPTCHA from "react-google-recaptcha";
import { Row, Column } from '@waffl';
import { useMixpanel } from 'gatsby-plugin-mixpanel';

// Styles
// ------------
import { Jacket, Text, FormJacket, ButtonJacket, Response, Content } from './styles';

// Component
// ------------
const ContactForm = ({ formSuccessMessage, formErrorMessage }) => {
    // NOTE • SITEKEY
    const sitekey = process.env.GATSBY_SITE_RECAPTCHA_KEY;
    const captchaRef = useRef();

    // NOTE • MIXPANEL
	const mixpanel = useMixpanel();

    // NOTE • Refs
    // ------
    const nameField = useRef();
    const emailField = useRef();

    // NOTE • States
    // ------
    const [formData, setFormData] = useState('');
    const [emailError, setEmailError] = useState(false);
    const [emailTest, setEmailTest] = useState('');
	const [responseGood, setResponseGood] = useState(false);
    const [responseError, setResponseError] = useState(false);
    // const [buttonDisabled, setButtonDisabled] = useState(true);
    const [captchaResponse, setCaptchaResponse] = useState(null);

    // NOTE • Regex
    // ------
    const validEmailRegex = RegExp(/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i);

    // NOTE • Handle Input Change
    // ------
    const handleChange = (e) => {
        if (e.target.type === "email") {
            setEmailTest({ value: e.target.value });
            const test = validEmailRegex.test(emailTest.value);
            setEmailError(!test);
        }

        setFormData({ ...formData, [e.target.name]: e.target.value });
    }

    const handleBlur = (e) => {
        if (e.target.type === "email") {
            setEmailTest({ value: e.target.value.trim().toLowerCase() });
            const test = validEmailRegex.test(emailTest.value);
            setEmailError(!test);
        }

        if(!emailError || e.target.value.length == 0) {
            setEmailError(false);
        }
    }

    // NOTE • Periodically correct the email validation
    // ------
    useEffect(() => {
        setTimeout(() => {
            if (emailField.current && emailField.current.matches(':-webkit-autofill')) {
                setEmailTest({ value: emailField.current.value.trim().toLowerCase() });
                const test = validEmailRegex.test(emailTest.value);
                setEmailError(!test);
            }
        }, 1000);
    });

    // NOTE • Handle Form Submission
    // ------
    const handleSubmit = (e) => {
        e.preventDefault();

        const recaptchaValue = captchaRef.current.getValue();

        function encode(data) {
			return Object.keys(data)
				.map(
					(key) => encodeURIComponent(key) + '=' + encodeURIComponent(data[key])
				)
				.join('&');
		}

        // console.log("form data" + formData);
        // console.log("recaptcha key" + sitekey);
        // console.log("recaptcha response" + recaptchaValue);

        const axiosOptions = {
			url: window.location.href,
			method: 'POST',
			headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
			body: encode({
                'form-name': e.target.getAttribute('name'),
                'g-recaptcha': sitekey,
                'g-recaptcha-response': recaptchaValue,
                ...formData
            }),
		};

        axios(axiosOptions)
            .then((response) => {
                setResponseGood(true);

                mixpanel.track(`Contact form submitted`);
    
                setTimeout(() => {
                    setFormData('');
                    setEmailError(false);
                    setEmailTest('');
                }, 3000);
    
                setTimeout(() => {
                    setResponseGood(false);
                }, 10000);
            })
            .catch((err) => {
                setResponseError(true);
    
                setTimeout(() => {
                    setFormData('');
                    setEmailError(false);
                    setEmailTest('');
                }, 3000);
    
                setTimeout(() => {
                    setResponseError(false);
                }, 10000);
            });
    }

    return (
        <Jacket pad>
            <Row isExpanded isCollapsed isOuter>
                <Column small={12} medium={10} pushMedium={1}>
                    <Row isExpanded>
                        <Column small={12} medium={4} xlarge={3} mpad>
                            <Text>Whether you’ve got questions about photography, want to ask about a shop item or an experience day with me, I’m all ears, ask away using this form and I’ll respond as quickly as possible!</Text>
                        </Column>
                        <Column small={12} medium={7} pushMedium={1} xlarge={8}>
                            
                            {responseGood || responseError ? (
                                <Response good={responseGood} bad={responseError}>
                                    <Content>
                                        {responseGood ? formSuccessMessage : formErrorMessage}
                                    </Content>
                                </Response>
                            ) : (
                                <FormJacket
                                    name='Photoscoper: Contact'
                                    method='POST'
                                    // data-netlify-honeypot="bot-field"
                                    data-netlify-recaptcha="true"
                                    data-netlify="true"
                                    onSubmit={handleSubmit}
                                >
                                    {/* <input type='hidden' name='bot-field' /> */}
                                    <input type='hidden' name='form-name' value='Photoscoper: Contact' />

                                    <Row isExpanded>
                                        <Column small={12} large={6}>
                                            <Input
                                                ref={nameField}
                                                isRequired
                                                onBlur={handleBlur}
                                                onChange={handleChange}
                                                label='Name*'
                                                type='text'
                                                name='name'
                                                value={formData.name ? formData.name : ''}
                                            />
                                        </Column>
                                        <Column small={12} large={6}>
                                            <Input
                                                ref={emailField}
                                                isRequired
                                                onBlur={handleBlur}
                                                onChange={handleChange}
                                                label='Email*'
                                                type='email'
                                                name='email'
                                                emailError={emailError}
                                                value={formData.email ? formData.email : ''}
                                            />
                                        </Column>
                                    </Row>

                                    <Row isExpanded>
                                        <Column small={12}>
                                            <Input
                                                isBig
                                                isRequired
                                                onBlur={handleBlur}
                                                onChange={handleChange}
                                                label='Your message*'
                                                type='textarea'
                                                name='message'
                                                value={formData.message ? formData.message : ''}
                                            />
                                        </Column>
                                    </Row>

                                    <Row isExpanded>
                                        <Column small={12}>
                                            <ReCAPTCHA
                                                ref={captchaRef}
                                                id="recaptcha-google"
                                                sitekey={sitekey}
                                                size="normal"
                                                badge="inline"
                                                theme="dark"
                                                // onVerify={verify}
                                                onChange={setCaptchaResponse}
                                            />
                                        </Column>
                                    </Row>

                                    <Row isExpanded>
                                        <Column small={12}>
                                            <ButtonJacket>
                                                <Button
                                                    isBtn
                                                    isNext
                                                    label='Send'
                                                    disabled={
                                                        !formData.name ||
                                                        !formData.email ||
                                                        !formData.message ||
                                                        !captchaResponse
                                                    }
                                                />
                                            </ButtonJacket>
                                        </Column>
                                    </Row>
                                </FormJacket>
                            )}

                        </Column>
                    </Row>
                </Column>
            </Row>
        </Jacket>
    );
}

export default ContactForm;

Any help highly appreciated.

Hey there,

Thanks so much for reaching out.

We cannot see any recaptcha implementation on your sites. Can you please send us a direct link to the recaptcha and error message that you are seeing? A direct reproduction will help us look into this further. If you do not want to implement this on your production site, can you set up a minimal reproduction that creates the same error?

Thanks!

Hey Hillary,

You can find the form here; https://www.photoscoper.co.uk/contact/

In the console on submission, I get a status of 400. In the recaptcha console I see submissions, but none that are pass or fail. Netlify doesn’t receive any submissions with recaptcha. If I take it off it’ll work fine.

Hey @adam12,

From what I can see, your code is not sending any data with the POST request.

This is what I see in dev tools:

Notice how devtools is not showing any “Payload” tab which would have been the case if there was any data sent.