Airtable sert souvent de couche d'orchestration pour des workflows de collecte, de traitement d'URL ou d'automatisation sans interface lourde. Quand un enregistrement Airtable doit lancer une action sur un service protégé par CAPTCHA, la limite apparaît vite. CaptchaAI permet d'intégrer la résolution directement dans vos Automations ou vos scripts Airtable, sans sortir du workflow métier.
L'idée n'est pas seulement de résoudre un CAPTCHA depuis Airtable, mais de faire d'un enregistrement un véritable job technique avec statut, horodatage, erreur et résultat réutilisable.
Cas concret
Vous stockez des URL cibles dans une table Airtable. Chaque URL correspond à une page qui demande un reCAPTCHA avant l'étape suivante de traitement. Lorsqu'un nouvel enregistrement arrive :
- Une Automation Airtable détecte le nouvel élément.
- Un script envoie les paramètres CAPTCHA à CaptchaAI.
- CaptchaAI renvoie un token résolu.
- Le token, le statut et l'horodatage sont enregistrés dans Airtable.
Structure de table recommandée
Créez une table nommée CAPTCHA Tasks avec les champs suivants :
| Champ | Type | Rôle |
|---|---|---|
| URL | URL | Page cible |
| Sitekey | Texte | Sitekey reCAPTCHA |
| Status | Single select | pending, solving, solved, failed |
| Token | Long text | Token CAPTCHA renvoyé |
| Solved At | Date/time | Date et heure de résolution |
| Error | Texte | Message d'erreur en cas d'échec |
Ce modèle simple suffit pour suivre l'état du job et relancer proprement les échecs sans bricoler des colonnes à chaque itération.
Étape 1 : créer l'Automation
Dans Airtable :
- Ouvrez l'onglet Automations.
- Cliquez sur Create automation.
- Donnez-lui un nom explicite, par exemple
Solve CAPTCHA on New Record.
Déclencheur
Choisissez When record matches conditions :
- Table :
CAPTCHA Tasks - Condition :
Statusest égal àpending
Ce choix est utile parce qu'il couvre à la fois les nouveaux enregistrements et les relances manuelles après échec.
Étape 2 : ajouter l'action de script
Ajoutez une action Run a script :
// Airtable Automation Script — Solve CAPTCHA via CaptchaAI
// Input configuration (set in the left panel):
// - recordId: Record ID from trigger
// - sitekey: Sitekey field from trigger
// - pageurl: URL field from trigger
const config = input.config();
const recordId = config.recordId;
const sitekey = config.sitekey;
const pageurl = config.pageurl;
const API_KEY = 'YOUR_API_KEY'; // Use input.config() for security
// Update status to "solving"
const table = base.getTable('CAPTCHA Tasks');
await table.updateRecordAsync(recordId, {
'Status': { name: 'solving' },
});
try {
// Step 1: Submit task to CaptchaAI
const submitUrl = `https://ocr.captchaai.com/in.php?key=${API_KEY}&method=userrecaptcha&googlekey=${encodeURIComponent(sitekey)}&pageurl=${encodeURIComponent(pageurl)}&json=1`;
const submitResponse = await fetch(submitUrl);
const submitResult = await submitResponse.json();
if (submitResult.status !== 1) {
throw new Error(`Submit failed: ${submitResult.request}`);
}
const taskId = submitResult.request;
console.log(`Task submitted: ${taskId}`);
// Step 2: Poll for result (wait 15 seconds first)
await new Promise(resolve => setTimeout(resolve, 15000));
let token = null;
for (let i = 0; i < 20; i++) {
const pollUrl = `https://ocr.captchaai.com/res.php?key=${API_KEY}&action=get&id=${taskId}&json=1`;
const pollResponse = await fetch(pollUrl);
const pollResult = await pollResponse.json();
if (pollResult.status === 1) {
token = pollResult.request;
break;
}
if (pollResult.request !== 'CAPCHA_NOT_READY') {
throw new Error(`Solve failed: ${pollResult.request}`);
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
if (!token) {
throw new Error('Polling timeout — CAPTCHA not solved in time');
}
// Step 3: Update record with solved token
await table.updateRecordAsync(recordId, {
'Status': { name: 'solved' },
'Token': token,
'Solved At': new Date().toISOString(),
'Error': '',
});
console.log(`CAPTCHA solved for record ${recordId}`);
} catch (error) {
// Update record with error
await table.updateRecordAsync(recordId, {
'Status': { name: 'failed' },
'Error': error.message,
});
console.error(`Failed: ${error.message}`);
}
Configurer les entrées de script
Dans le panneau de gauche de l'action de script, mappez les variables d'entrée :
recordId-> Record ID issu du triggersitekey-> champSitekeypageurl-> champURL
En production, pensez à passer la clé API via input.config() ou une variable secrète plutôt qu'en dur dans le script.
Étape 3 : traitement par lot avec Scripting Extension
Si vous voulez traiter plusieurs enregistrements en une fois, utilisez la Scripting extension d'Airtable :
// Batch CAPTCHA Solver — Airtable Scripting Extension
const API_KEY = 'YOUR_API_KEY';
const table = base.getTable('CAPTCHA Tasks');
// Get all pending records
const query = await table.selectRecordsAsync({
fields: ['URL', 'Sitekey', 'Status'],
});
const pendingRecords = query.records.filter(
r => r.getCellValueAsString('Status') === 'pending'
);
output.text(`Found ${pendingRecords.length} pending CAPTCHAs`);
for (const record of pendingRecords) {
const sitekey = record.getCellValueAsString('Sitekey');
const pageurl = record.getCellValueAsString('URL');
if (!sitekey || !pageurl) {
output.text(`Skipping ${record.id} — missing sitekey or URL`);
continue;
}
output.text(`Solving for: ${pageurl}`);
await table.updateRecordAsync(record.id, {
'Status': { name: 'solving' },
});
try {
// Submit
const submitResp = await fetch(
`https://ocr.captchaai.com/in.php?key=${API_KEY}&method=userrecaptcha&googlekey=${encodeURIComponent(sitekey)}&pageurl=${encodeURIComponent(pageurl)}&json=1`
);
const submitData = await submitResp.json();
if (submitData.status !== 1) throw new Error(submitData.request);
// Poll
await new Promise(r => setTimeout(r, 15000));
let token = null;
for (let i = 0; i < 20; i++) {
const pollResp = await fetch(
`https://ocr.captchaai.com/res.php?key=${API_KEY}&action=get&id=${submitData.request}&json=1`
);
const pollData = await pollResp.json();
if (pollData.status === 1) { token = pollData.request; break; }
if (pollData.request !== 'CAPCHA_NOT_READY') throw new Error(pollData.request);
await new Promise(r => setTimeout(r, 5000));
}
if (!token) throw new Error('Timeout');
await table.updateRecordAsync(record.id, {
'Status': { name: 'solved' },
'Token': token,
'Solved At': new Date().toISOString(),
});
output.text(`✓ Solved: ${pageurl}`);
} catch (e) {
await table.updateRecordAsync(record.id, {
'Status': { name: 'failed' },
'Error': e.message,
});
output.text(`✗ Failed: ${e.message}`);
}
}
output.text('Batch processing complete');
Dépannage
| Probleme | Cause probable | Correctif |
|---|---|---|
| L'automatisation ne part pas | Le record ne correspond pas à pending |
Vérifiez exactement la valeur du champ Status |
fetch is not defined |
Selon le contexte Airtable, il faut remoteFetchAsync |
Essayez remoteFetchAsync à la place |
| Le script expire | Les Automations ont une limite de temps courte | Réduisez le nombre de polls et augmentez le délai initial |
| La mise à jour du record échoue | Noms de champs incohérents | Vérifiez les labels exacts utilisés dans updateRecordAsync |
| La clé API est visible | Clé codée en dur | Utilisez input.config() avec un secret |
FAQ
Quelle est la limite de temps d'exécution d'un script dans Airtable ?
Pour les Automations, la fenêtre est courte, donc il faut éviter un polling trop dense. Si le solve prend plus longtemps, augmentez le délai initial et réduisez le nombre d'itérations. La Scripting extension laisse un peu plus de souplesse pour des traitements manuels ou par lot.
Peut-on utiliser le même schéma pour les CAPTCHA image ?
Oui. Il suffit de changer method pour un mode adapté au type de CAPTCHA et de transmettre l'image ou les paramètres attendus. Airtable peut servir de couche de stockage et de reprise pour ces jobs aussi.
Comment protéger la clé API ?
Dans une Automation, utilisez les variables d'entrée ou un secret. Dans la Scripting extension, vous pouvez la demander à l'exécution avec input.textAsync() si vous ne voulez pas la stocker dans le code.
Peut-on relancer les échecs ?
Oui. Remettez le champ Status sur pending pour relancer l'automation. Ajoutez un compteur de retries si vous voulez éviter les boucles infinies.
Articles connexes
- Comment résoudre le callback reCAPTCHA v2 avec l'API
- Gérer reCAPTCHA v2 et Turnstile sur le même site
- Comprendre le callback reCAPTCHA v2
Prochaines étapes
Si Airtable pilote déjà vos opérations, récupérez votre clé API CaptchaAI et transformez chaque enregistrement critique en tâche de résolution traçable et rejouable.
Guides associes :
- Google Apps Script et CaptchaAI
- Zapier et CaptchaAI pour l'automatisation no-code
- Make et CaptchaAI pour automatiser la résolution