diff --git a/packages/clerk-js/src/utils/__tests__/captcha.test.ts b/packages/clerk-js/src/utils/__tests__/captcha.test.ts index f2e65933bd9..cec37f051e4 100644 --- a/packages/clerk-js/src/utils/__tests__/captcha.test.ts +++ b/packages/clerk-js/src/utils/__tests__/captcha.test.ts @@ -14,9 +14,11 @@ describe('shouldRetryTurnstileErrorCode', () => { ['104xxx', true], ['106xxx', true], ['110600', true], + ['200', true], + ['200100', true], + ['200xxx', true], ['300xxx', true], ['600xxx', true], - ['200010', false], ['100405', false], ['105001', false], ['110430', false], diff --git a/packages/clerk-js/src/utils/captcha/turnstile.ts b/packages/clerk-js/src/utils/captcha/turnstile.ts index 40cce095d46..f9378e77ec3 100644 --- a/packages/clerk-js/src/utils/captcha/turnstile.ts +++ b/packages/clerk-js/src/utils/captcha/turnstile.ts @@ -23,7 +23,7 @@ declare global { } export const shouldRetryTurnstileErrorCode = (errorCode: string) => { - const codesWithRetries = ['crashed', 'undefined_error', '102', '103', '104', '106', '110600', '300', '600']; + const codesWithRetries = ['crashed', 'undefined_error', '102', '103', '104', '106', '110600', '200', '300', '600']; return !!codesWithRetries.find(w => errorCode.startsWith(w)); }; @@ -117,7 +117,8 @@ export const getTurnstileToken = async (opts: CaptchaOptions) => { // smart widget with container provided by user if (!widgetContainerQuerySelector && widgetType === 'smart') { - const visibleDiv = document.getElementById(CAPTCHA_ELEMENT_ID); + // Use waitForElement to ensure the element is ready, similar to modal approach + const visibleDiv = await waitForElement(`#${CAPTCHA_ELEMENT_ID}`).catch(() => null); if (visibleDiv) { captchaTypeUsed = 'smart'; captchaWidgetType = 'smart'; @@ -147,8 +148,15 @@ export const getTurnstileToken = async (opts: CaptchaOptions) => { } const handleCaptchaTokenGeneration = async (): Promise<[string, string]> => { - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { try { + // Re-verify element exists right before render to prevent 200100 errors + const containerElement = await waitForElement(widgetContainerQuerySelector); + if (!containerElement) { + reject(['Widget container element not found', undefined]); + return; + } + const id = captcha.render(widgetContainerQuerySelector, { sitekey: turnstileSiteKey, appearance: 'interaction-only',