Maps/Leads Novelty Gate avatar

Maps/Leads Novelty Gate

Under maintenance

Pricing

from $0.025 / novelty report

Go to Apify Store
Maps/Leads Novelty Gate

Maps/Leads Novelty Gate

Under maintenance

Run 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

FG EI

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Security

Limited permissions

Share

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 install
npm test
npm run build
npm 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 build
mkdir -p storage/key_value_stores/default
cp store/examples/input-inline-seed.json storage/key_value_stores/default/INPUT.json
APIFY_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-cli
apify login
apify 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

ChampDéfautRôle
datasetId ou items—Dataset du scrape courant, ou lignes inline. Un seul des deux.
historyDatasetId ou historyKeyValueStoreIdstore nomméHistorique dans ton compte. Les deux ensemble = erreur.
historyKeyNOVELTY_HISTORYClé KV. Ignorée sans id de store, sauf si tu mets une clé custom (alors l’id est obligatoire).
identityModeautoplaceId, email, ou auto.
emitModenew_onlyseed_history_only n’émet rien. new_and_changed est différé et fait échouer le run.
failIfNoveltyRateBelownon défini0–1. Échec si le taux est strictement inférieur. Ignoré au seed.
updateHistorytrueÉcrit les NEW. Un gate en échec n’écrit pas.
normalizeEmailtrueminuscules, 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 lue
  • novelty-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 / scraper
  • store/PUBLISH_CHECKLIST.md
  • store/tracking/gates.json — J0 / J7 / J30 / J60, seuils du gate, J0 encore vide
  • store/examples/ — inputs et forme du rapport