Notification Grist sans webhook (solution ActivePieces)

Bonjour à tous,

Je viens partager une petite découverte que j’ai faite aujourd’hui.

Je n’ai pas trouvé de solution existante pour contourner le blocage des triggers (webhooks) sur Grist/DINUM, donc je ne sais pas si cela a déjà été proposé, mais voici une approche qui fonctionne de mon côté.

J’ai mis en place un workflow sur ActivePieces (version gratuite) pour gérer l’envoi de notifications par mail lorsqu’une nouvelle entrée est ajoutée dans une table.

L’idée est simple :

  • Utiliser un trigger planifié (schedule) au lieu des triggers classiques
  • Récupérer les enregistrements via une recherche
  • Comparer la date de l’entrée avec la date actuelle
  • Si la date correspond à aujourd’hui → on considère qu’il s’agit d’une nouvelle sollicitation → envoi d’un email

:point_right: Cela permet de contourner le blocage des webhooks.
Voici le workflow utilisé :

  • Schedule (toutes les X minutes)
  • Code (récupération de la date du jour)
  • Grist → recherche des enregistrements
  • Router / condition → comparaison des dates
  • Gmail → envoi de la notification ( dans mon cas, seul SMTP que j’ai trouvé)

Ca fonctionne bien et je pense que ça peut être adapté / amélioré selon les usages de chacun.

Si certains ont déjà testé d’autres approches ou ont des optimisations, je suis preneur :slightly_smiling_face:

J’aimerai bien ajouter l’image de mon workflow mais je n’y arrive pas pour le moment

En attendant voila le fichier json à enregistrer en .json et peut être importé directement dans Active piecies

📦 Workflow ActivePieces (JSON importable)
{
  "name": "Workflow notification",
  "type": "SHARED",
  "summary": "",
  "description": "",
  "tags": [],
  "blogUrl": "",
  "metadata": {
    "externalId": "4uCkJJU0ROOQ2AC0MVE3f"
  },
  "author": "rachid rahal",
  "categories": [],
  "pieces": [
    "@activepieces/piece-schedule",
    "@activepieces/piece-grist",
    "@activepieces/piece-gmail"
  ],
  "flows": [
    {
      "displayName": "Workflow notification",
      "trigger": {
        "name": "trigger",
        "valid": true,
        "displayName": "Toutes les heures",
        "nextAction": {
          "name": "step_3",
          "skip": false,
          "type": "CODE",
          "valid": true,
          "settings": {
            "input": {},
            "sampleData": {},
            "sourceCode": {
              "code": "export const code = async (inputs) => {\n  const today = new Date();\n\n  const formattedDate = today.toISOString().split('T')[0];\n\n  return formattedDate;\n};",
              "packageJson": "{}"
            },
            "errorHandlingOptions": {
              "retryOnFailure": {
                "value": false
              },
              "continueOnFailure": {
                "value": false
              }
            }
          },
          "nextAction": {
            "name": "step_2",
            "skip": false,
            "type": "PIECE",
            "valid": true,
            "settings": {
              "input": {
                "auth": "{{connections['jBvomKtWUm4yoX0KurJPG']}}",
                "value": "{{step_3}}",
                "column": "date_AP",
                "table_id": "DEMANDE_LAB",
                "document_id": "fXqbFbtqnu7NkgU6uACu7D",
                "workspace_id": 10706
              },
              "pieceName": "@activepieces/piece-grist",
              "actionName": "grist-search-record",
              "sampleData": {},
              "pieceVersion": "0.1.4",
              "propertySettings": {
                "value": {
                  "type": "MANUAL"
                },
                "column": {
                  "type": "MANUAL"
                },
                "table_id": {
                  "type": "MANUAL"
                },
                "document_id": {
                  "type": "MANUAL"
                },
                "workspace_id": {
                  "type": "MANUAL"
                }
              },
              "errorHandlingOptions": {
                "retryOnFailure": {
                  "value": false
                },
                "continueOnFailure": {
                  "value": false
                }
              }
            },
            "nextAction": {
              "name": "step_4",
              "skip": false,
              "type": "ROUTER",
              "valid": true,
              "children": [
                {
                  "name": "step_1",
                  "skip": false,
                  "type": "PIECE",
                  "valid": true,
                  "settings": {
                    "input": {
                      "cc": [],
                      "bcc": [],
                      "auth": "{{connections['YfZSMNuHwnXezLrCM9DkB']}}",
                      "body":"Nouvelle sollicitation du lab ",
                      "from": "innovmandie@normandie.gouv.fr",
                      "draft": false,
                      "subject": "Nouvelle sollicitation du lab ",
                      "receiver": [
                        "tes@gmail.com"
                      ],
                      "reply_to": [],
                      "body_type": "html",
                      "attachments": [],
                      "sender_name": "Innovmandie"
                    },
                    "pieceName": "@activepieces/piece-gmail",
                    "actionName": "send_email",
                    "sampleData": {},
                    "pieceVersion": "0.12.2",
                    "propertySettings": {
                      "cc": {
                        "type": "MANUAL"
                      },
                      "bcc": {
                        "type": "MANUAL"
                      },
                      "body": {
                        "type": "MANUAL"
                      },
                      "from": {
                        "type": "MANUAL"
                      },
                      "draft": {
                        "type": "MANUAL"
                      },
                      "subject": {
                        "type": "MANUAL"
                      },
                      "receiver": {
                        "type": "MANUAL"
                      },
                      "reply_to": {
                        "type": "MANUAL"
                      },
                      "body_type": {
                        "type": "MANUAL"
                      },
                      "attachments": {
                        "type": "MANUAL"
                      },
                      "in_reply_to": {
                        "type": "MANUAL"
                      },
                      "sender_name": {
                        "type": "MANUAL"
                      }
                    },
                    "errorHandlingOptions": {
                      "retryOnFailure": {
                        "value": false
                      },
                      "continueOnFailure": {
                        "value": false
                      }
                    }
                  },
                  "displayName": "Envoyer un e-mail",
                  "lastUpdatedDate": "2026-04-22T08:49:03.850Z"
                },
                null
              ],
              "settings": {
                "branches": [
                  {
                    "branchName": "Branch 1",
                    "branchType": "CONDITION",
                    "conditions": [
                      [
                        {
                          "operator": "LIST_IS_NOT_EMPTY",
                          "firstValue": "{{step_2['records']}}"
                        }
                      ]
                    ]
                  },
                  {
                    "branchName": "Otherwise",
                    "branchType": "FALLBACK"
                  }
                ],
                "sampleData": {},
                "executionType": "EXECUTE_FIRST_MATCH"
              },
              "displayName": "Router",
              "lastUpdatedDate": "2026-04-22T08:48:29.752Z"
            },
            "displayName": "Rechercher un enregistrement",
            "lastUpdatedDate": "2026-04-22T08:48:29.751Z"
          },
          "displayName": "Code",
          "lastUpdatedDate": "2026-04-22T08:48:29.751Z"
        },
        "lastUpdatedDate": "2026-04-22T08:48:29.751Z",
        "type": "PIECE_TRIGGER",
        "settings": {
          "propertySettings": {
            "run_on_weekends": {
              "type": "MANUAL"
            }
          },
          "pieceName": "@activepieces/piece-schedule",
          "pieceVersion": "0.1.17",
          "triggerName": "every_hour",
          "input": {
            "run_on_weekends": false
          }
        }
      },
      "valid": true,
      "schemaVersion": "20",
      "notes": []
    }
  ],
  "status": "PUBLISHED"

}
2 « J'aime »

Bonjour,

Vous avez résumé les 2 uniques façon d’être notifié:

  • Soit c’est Grist qui vous l’indique (WebHook)
  • Soit c’est vous qui requêtez Grist et appliquez des règles de gestions pour détecter les nouvelles données (votre workflow ActivePieces)

Avec cette 2 solutions, que j’applique également, vous allez vite être heurtés au rate limite de l’API (de mémoire 20 requêtes/secondes). Autrement, si vous appliquez votre workflow sur 21 tables différentes, vous aurez des erreurs lors des appels API.
Sachant qu’un document Grist contient plusieurs tables, cette limite peut très vite être atteinte (surtout qu’il s’agit d’une limite par IP il me semble, à minima par token/user).

Pour palier cette limite, je requête l’API Grist pour télécharger le document au format SQLite puis j’applique mes règles les tables de ce fichier directement. Ce qui représente au total 1 seule requête du document tous les X minutes que 1 requête par table pour chaque document concernés.
A terme, le même problème se posera mais en jouant sur les heures de déclenchement, on peut facilement monter à plusieurs 10aines de documents avant d’avant d’atteindre la limite

2 « J'aime »

Merci beaucoup pour l’information !

Pour l’instant, je n’applique mon workflow que sur une seule table, donc je ne suis pas encore confronté à cette limite, mais c’est clairement un bon point à savoir

je garde ça en tête pour la suite ! :smile:

Pour bien comprendre, est-ce que le mail envoyé part forcément d’une adresse Gmail ? Ou est-ce qu’on utilise juste le SMTP de Google avec n’importe quelle adresse d’expédition qu’on aurait configurée ?

Merci :slight_smile:

Je n’ai jamais testé l’envoi avec un alias, mais côté ActivePieces il y a bien un champ “From Email” dans l’action SMTP, donc techniquement tu peux définir l’adresse d’expédition.

Après, en pratique, ça dépend surtout de la configuration côté SMTP (SPF/DKIM, alias autorisé, etc.).
Avec Gmail notamment, il faut généralement que l’adresse soit déclarée comme alias, sinon elle peut être refusée ou réécrite.

Donc en théorie je dirais : oui possible, mais à tester…

1 « J'aime »