Maps/Leads Novelty Gate
Under maintenancePricing
from $0.025 / novelty report
Maps/Leads Novelty Gate
Under maintenanceRun after each Google Maps or leads scrape: keeps a persistent placeId/email history in your account and outputs only leads never seen before. No scraping.
Pricing
from $0.025 / novelty report
Rating
0.0
(0)
Developer
FG EI
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Security
Limited permissionsShare
Après un scrape Maps ou leads, ne garder que les fiches (placeId / email) jamais vues dans ton historique Apify, avec un échec optionnel si le taux de nouveauté est trop bas.
Brouillon local. Pas publié sur le Store. Pas de pricing live.
Ce n’est pas un déduplicateur intra-batch, pas un filtre de champs, pas un scraper. Aucun fetch Google Maps. L’historique vit dans ton Dataset ou key-value store, jamais dans un stockage partagé.
Commandes
npm installnpm testnpm run buildnpm run smoke:local
npm test lance Vitest (seed, second run à 0 NEW, placeId, email, auto, ids invalides, doublons, gate PASS/FAIL, dataset vide, stockage, pas d’exfiltration).
npm run smoke:local enchaîne deux runs du binaire (dist/main.js) sur le stockage local : seed puis 0 NEW.
Lancer avec l’input Apify
npm run buildmkdir -p storage/key_value_stores/defaultcp store/examples/input-inline-seed.json storage/key_value_stores/default/INPUT.jsonAPIFY_LOCAL_STORAGE_DIR="$PWD/storage" CRAWLEE_STORAGE_DIR="$PWD/storage" npm start
Le rapport est dans storage/key_value_stores/default/NOVELTY_REPORT.json. L’historique seed est dans storage/key_value_stores/maps-leads-novelty-history/NOVELTY_HISTORY.json.
Sur la plateforme Apify (compte utilisateur, après un apify push privé) :
npm install -g apify-cliapify loginapify push
apify push met à jour un Actor privé. Il ne publie pas le Store et n’applique pas les prix. Ne pas cliquer sur Publish. Ne pas ouvrir Monetization. Détail : store/PUBLISH_CHECKLIST.md.
Entrées
| Champ | Défaut | Rôle |
|---|---|---|
datasetId ou items | — | Dataset du scrape courant, ou lignes inline. Un seul des deux. |
historyDatasetId ou historyKeyValueStoreId | store nommé | Historique dans ton compte. Les deux ensemble = erreur. |
historyKey | NOVELTY_HISTORY | Clé KV. Ignorée sans id de store, sauf si tu mets une clé custom (alors l’id est obligatoire). |
identityMode | auto | placeId, email, ou auto. |
emitMode | new_only | seed_history_only n’émet rien. new_and_changed est différé et fait échouer le run. |
failIfNoveltyRateBelow | non défini | 0–1. Échec si le taux est strictement inférieur. Ignoré au seed. |
updateHistory | true | Écrit les NEW. Un gate en échec n’écrit pas. |
normalizeEmail | true | minuscules, trim, suppression de %20 et des espaces. |
auto : placeId (aussi place_id, googlePlaceId) s’il est présent, sinon un email par adresse (email / emails[]), sinon repli moins fiable : hash name + address, ou téléphone déjà en E.164. Le repli ne s’applique pas en mode placeId ou email. Aucun indicatif pays n’est deviné.
Sorties
- Dataset du run : uniquement les lignes NEW (vide au premier run, en
seed_history_only, et si le gate échoue). Champs ajoutés :noveltyStatus,noveltyIdentityType,noveltyIdentityKey. - Key-value du run, clé
NOVELTY_REPORT:itemsScanned,newCount,knownCount,skippedNoIdentity,intraRunDupes,noveltyRate,identityModeUsed,historyUpdated,firstRun, plus l’état du gate et les warnings.
noveltyRate = newCount / (newCount + knownCount). Au seed, le taux est null (pas 1.0).
Historique et premier run
Premier run (pas d’id, ou store/dataset accessible mais vide) : toutes les identités vont dans l’historique, aucune fiche n’est émise, le run réussit. Le rapport indique où écrire l’id pour la suite.
Sans id, le seed ouvre ou crée le key-value store nommé maps-leads-novelty-history (clé NOVELTY_HISTORY) dans le compte du run. Le run suivant sans id réutilise ce nom.
Un id fourni mais inaccessible, ou un document d’historique illisible, échoue. On ne traite pas un historique cassé comme « tout est nouveau ».
Contenu stocké : { identityKey, identityType, firstSeenAt, lastSeenAt }. Pas la fiche entière. Un email utilisé comme identité reste dans ton stockage : c’est le point de comparaison, il ne sort pas du compte.
Plafonds
Plus de 100 000 lignes en entrée, ou plus de 500 000 enregistrements d’historique : le run échoue, sans couper en silence.
Prix (proposition seulement)
PPE_SAFE_TO_APPLY = NO. Voir store/PPE_PROPOSAL.md.
apify-actor-start$0.00005 (événement plateforme, pas chargé dans le code)items-scanned$0.00005 / ligne luenovelty-report$0.025, événement primaire, 1× par run réussi
Run minimal (3 lignes) ≈ $0.0252. Run typique (2 000 lignes) ≈ $0.12505.
Fichiers utiles
docs/DECISIONS.md— ce qui est figé, et pourquoi CHANGED n’est pas implémentéstore/WORDING.md— texte Store vs dedup / filtre / scraperstore/PUBLISH_CHECKLIST.mdstore/tracking/gates.json— J0 / J7 / J30 / J60, seuils du gate, J0 encore videstore/examples/— inputs et forme du rapport