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.