Pour connecter GA4 à ChatGPT, vous pouvez utiliser une passerelle personnelle qui lit vos rapports Google Analytics 4 et les transmet à ChatGPT par un tunnel privé. Vous pouvez ensuite interroger vos données en français : sources de trafic, pages consultées, événements clés ou achats enregistrés. Dans la méthode présentée ici, l'accès est limité à la lecture.
Cette installation a été réalisée chez DOPHIS et validée depuis ChatGPT le 30 octobre 2026. Elle repose sur un compte de service Google, la Google Analytics Data API, un serveur MCP en Python et le client de tunnel OpenAI. Le tutoriel reprend ces étapes avec des paramètres génériques, à remplacer par ceux de votre propre propriété.
Que peut-on analyser avec GA4 connecté à ChatGPT ?
La connexion évite de préparer un nouvel export pour chaque question. ChatGPT peut demander un rapport à la passerelle, lire les résultats renvoyés par Google, puis comparer des périodes ou détailler les chiffres selon vos besoins.
- Identifier les sources et les canaux qui apportent des sessions
- Comparer les pages d'entrée et les pages consultées
- Répartir le trafic par pays ou par appareil
- Examiner les événements enregistrés pour les formulaires et les téléchargements
- Analyser les achats et les revenus lorsque le suivi e-commerce fonctionne
Ce raccordement concerne les rapports GA4. Il ne donne pas automatiquement accès à Google Ads, à Search Console, à WordPress ou aux commandes de votre boutique. Chaque source doit être connectée séparément.
Comment fonctionne la passerelle en lecture seule ?
Le serveur MCP est un petit programme qui expose des fonctions utilisables par ChatGPT. Il fonctionne sur votre ordinateur. Lors d'une demande, il s'authentifie auprès de Google, interroge la propriété autorisée et renvoie le rapport. Le tunnel OpenAI transporte les échanges entre ce programme local et ChatGPT.
| Élément | Rôle dans la connexion |
|---|---|
| Propriété GA4 | Contient les données collectées pour votre site ou votre application |
| Compte de service Google | Identifie le programme auprès de Google et reçoit le rôle Lecteur sur la propriété |
| Google Analytics Data API | Fournit les rapports demandés |
| Passerelle Python / MCP | Limite les opérations disponibles et met les résultats à disposition de ChatGPT |
| Tunnel privé OpenAI | Relie ChatGPT au programme local par une connexion sortante |
La lecture seule repose ici sur trois éléments complémentaires : le rôle Lecteur dans GA4, l'autorisation technique analytics.readonly et un programme qui ne propose aucune fonction de modification. La propriété est définie dans le code ; les outils ne permettent pas d'en choisir une autre.
Le serveur reste local, mais les rapports demandés sont bien transmis à ChatGPT. Un tunnel privé ne signifie donc pas que les données restent exclusivement sur votre ordinateur.
Quels accès faut-il préparer ?
Cette méthode évite de souscrire un abonnement à un connecteur d'analyse tiers. Elle suppose toutefois que votre compte ChatGPT et votre espace de travail permettent l'ajout d'un serveur MCP personnel et l'utilisation d'un tunnel. Vérifiez la présence de ces options avant de commencer ; leur disponibilité dépend de votre accès et des règles de votre organisation.
| À prévoir | Pourquoi |
|---|---|
| Un accès administrateur à la propriété GA4 | Ajouter le compte de service comme Lecteur |
| Un projet Google Cloud et les droits nécessaires | Activer la Data API et créer ou réutiliser un compte de service |
| Un PC Windows connecté à Internet | Exécuter la passerelle et le client de tunnel |
| Python 3.11 ou plus récent | Exécuter le serveur fourni dans ce tutoriel |
| Un accès aux tunnels OpenAI | Créer le tunnel et disposer d'une clé autorisée à l'utiliser |
Les requêtes Google restent soumises aux quotas de la Google Analytics Data API. Le code ci-dessous n'appelle pas un modèle par l'API OpenAI : ChatGPT utilise la passerelle comme un outil. Cela ne constitue pas une promesse de gratuité de toutes les offres ChatGPT ou de tous les services associés.
1. Activer la Google Analytics Data API
Ouvrez la console Google Cloud et sélectionnez votre projet. Si vous avez déjà créé un projet pour une passerelle Google Ads ou Search Console, vous pouvez le réutiliser.
- Ouvrez API et services → Bibliothèque
- Recherchez Google Analytics Data API
- Vérifiez le projet sélectionné, puis cliquez sur Activer
Si le bouton indique « Gérer », l'API est déjà activée. Pour la passerelle de cet article, la Data API suffit : elle lit les rapports et la liste des dimensions et métriques. La Google Analytics Admin API n'est pas utilisée.
Le guide de démarrage de la Data API détaille l'authentification et le premier appel de rapport.
2. Donner un accès Lecteur au compte de service
Créer ou réutiliser le compte Google du programme
Si un compte de service existe déjà pour vos autres passerelles, vous pouvez réutiliser son adresse et sa clé JSON. Dans notre installation, c'est ce qui a permis d'ajouter GA4 sans recréer tous les accès Google.
Pour une première connexion, ouvrez IAM et administration → Comptes de service dans Google Cloud, puis créez un compte de service. Son adresse se termine par iam.gserviceaccount.com. Pour ce montage, il n'est pas nécessaire de lui attribuer le rôle Propriétaire ou Éditeur du projet Cloud : l'accès aux rapports sera accordé dans GA4.
Depuis la fiche de ce compte, ouvrez Clés → Ajouter une clé → Créer une clé, choisissez le format JSON et téléchargez le fichier. Si la création de clés est bloquée par votre organisation, faites examiner cette règle par son administrateur.
Conservez ce fichier dans un dossier local non partagé. Il contient une clé privée : ne le joignez pas à une conversation et ne le déposez pas dans la médiathèque WordPress. La documentation Google sur les clés de compte de service précise leur création et leur suppression.
Ajouter le compte dans Google Analytics
- Dans Google Analytics, sélectionnez la propriété à connecter
- Ouvrez Administration → Gestion des accès à la propriété
- Cliquez sur + → Ajouter des utilisateurs
- Renseignez l'adresse du compte de service
- Décochez la notification par e-mail, sélectionnez Lecteur, puis validez
Ajoutez le compte au niveau de la propriété concernée. Le tableau des rôles et restrictions GA4 confirme que le rôle Lecteur permet de consulter les données par API. Des restrictions sur les métriques de coût ou de revenu peuvent limiter certains rapports.
3. Récupérer l'ID numérique de la propriété GA4
Dans Administration → Paramètres de la propriété → Détails de la propriété, copiez l'ID de propriété. Il est composé uniquement de chiffres.
L'ID attendu est celui de la propriété, par exemple 123456789. Ce nombre est un exemple fictif. N'utilisez pas l'identifiant de mesure commençant par G-, ni l'ID du compte Analytics ou celui d'un flux de données.
4. Installer la passerelle sur Windows
Les fichiers ci-dessous constituent une version générique de la passerelle utilisée pour notre connexion. Les fonctions de lecture suivent le même principe ; les chemins, le nom du connecteur et les paramètres sont indépendants de DOPHIS. Le code est inclus dans l'article pour éviter de dépendre d'une archive personnelle.
Installez Python 3.11 ou plus récent depuis la page officielle Python pour Windows, puis ouvrez Windows PowerShell. Vérifiez la commande python --version. Si elle est introuvable, terminez l'installation de Python et rouvrez PowerShell avant de poursuivre.
Préparer le dossier et les dépendances
Créez le dossier suivant, puis placez-y votre fichier JSON sous le nom google-service-account.json. Ce nom est choisi pour le tutoriel ; il n'est pas imposé par Google.
New-Item -ItemType Directory -Force -Path 'C:\Connecteur_IA\GA4'
Set-Location -LiteralPath 'C:\Connecteur_IA\GA4'
python -m venv venv
Créez un fichier requirements.txt dans ce dossier et copiez-y ces lignes. Elles correspondent aux versions utilisées lors de la préparation de ce tutoriel.
mcp==1.30.0
google-auth[requests]==2.62.0
requests==2.34.2
Installez ensuite les dépendances. Attendez la fin de cette commande et vérifiez qu'elle ne se termine pas par une erreur.
.\venv\Scripts\python.exe -m pip install --index-url https://pypi.org/simple -r .\requirements.txt
Créer le serveur MCP
Enregistrez le code suivant en UTF-8 dans ga4_server.py, dans le même dossier. Dans la ligne PROPERTY_ID = "VOTRE_ID_GA4", remplacez VOTRE_ID_GA4 par votre ID numérique en conservant les guillemets. Vérifiez que Windows n'a pas ajouté une extension .txt au nom du fichier.
Afficher le code complet de ga4_server.py
"""GA4 personnel: passerelle MCP stdio, rapports en lecture seule."""
from __future__ import annotations
import argparse
import json
import math
import os
import re
import sys
from datetime import date
from pathlib import Path
from typing import Literal
from google.auth.exceptions import GoogleAuthError
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account
from mcp.server.fastmcp import FastMCP
from mcp.types import ToolAnnotations
from pydantic import BaseModel, ConfigDict, Field
from requests.exceptions import RequestException
VERSION = "1.0.0"
PROPERTY_ID = "VOTRE_ID_GA4"
PROPERTY = "properties/" + PROPERTY_ID
ENDPOINT = "https://analyticsdata.googleapis.com/v1beta/" + PROPERTY
SCOPES = ("https://www.googleapis.com/auth/analytics.readonly",)
DEFAULT_CREDENTIALS = str(Path(__file__).with_name("google-service-account.json"))
FIELD_PATTERN = r"^[A-Za-z][A-Za-z0-9_:\[\].-]$"
class GA4Error(RuntimeError):
"""Message public local; aucun contenu de cle ou de reponse d'erreur distante."""
class DimensionFilter(BaseModel):
model_config = ConfigDict(extra="forbid")
field: str = Field(pattern=FIELD_PATTERN)
match_type: Literal["EXACT", "BEGINS_WITH", "ENDS_WITH", "CONTAINS", "FULL_REGEXP", "PARTIAL_REGEXP"] = "EXACT"
value: str = Field(max_length=4096)
case_sensitive: bool = False
negate: bool = False
def _session() -> AuthorizedSession:
path = Path(os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", DEFAULT_CREDENTIALS))
try:
info = json.loads(path.read_text(encoding="utf-8-sig"))
if not isinstance(info, dict) or info.get("type") != "service_account":
raise GA4Error("Le fichier Google doit etre une cle de compte de service.")
if info.get("token_uri") != "https://oauth2.googleapis.com/token":
raise GA4Error("Adresse d'authentification Google inattendue dans le fichier local.")
credentials = service_account.Credentials.from_service_account_info(info, scopes=SCOPES)
return AuthorizedSession(credentials, refresh_timeout=20, max_refresh_attempts=1)
except GA4Error:
raise
except FileNotFoundError:
raise GA4Error("Fichier Google absent. Placer google-service-account.json a cote de ga4_server.py.") from None
except (OSError, ValueError, GoogleAuthError, KeyError, TypeError):
raise GA4Error("Impossible de lire la cle Google locale. Verifier le fichier et les droits Windows.") from None
def _read_google(operation: str, body: dict | None = None) -> dict:
if not re.fullmatch(r"[0-9]+", PROPERTY_ID):
raise GA4Error("Remplacer VOTRE_ID_GA4 par votre ID numerique dans PROPERTY_ID.")
# Liste fermee: le POST runReport est une lecture. Aucune URL fournie par l'appelant.
routes =
if operation not in routes:
raise GA4Error("Operation non autorisee: passerelle en lecture seule.")
method, url = routes[operation]
try:
with _session() as session:
response = session.request(method, url, json=body, timeout=(10, 40), allow_redirects=False)
except GA4Error:
raise
except GoogleAuthError:
raise GA4Error("Authentification Google refusee. Verifier que le compte de service et sa cle sont actifs.") from None
except RequestException:
raise GA4Error("Connexion Google impossible ou delai depasse. Verifier Internet et reessayer.") from None
if response.status_code != 200:
hints =
raise GA4Error(f"Google HTTP . " + hints.get(response.status_code, "Service indisponible ou reponse inattendue. Reessayer plus tard."))
try:
result = response.json()
except ValueError:
raise GA4Error("Google a renvoye une reponse JSON invalide.") from None
if not isinstance(result, dict):
raise GA4Error("Format de reponse Google inattendu.")
return result
def _date_key(value: str):
if not isinstance(value, str):
raise GA4Error("Date invalide: utiliser AAAA-MM-JJ, NdaysAgo, yesterday ou today.")
if value in :
return ("relative", 0 if value == "today" else -1)
if re.fullmatch(r"[0-9]daysAgo", value):
return ("relative", -int(value[:-7]))
if re.fullmatch(r"[0-9]-[0-9]-[0-9]", value):
try:
return ("absolute", date.fromisoformat(value))
except ValueError:
pass
raise GA4Error("Date invalide: utiliser AAAA-MM-JJ, NdaysAgo, yesterday ou today.")
def _fields(values: list[str], maximum: int, label: str, minimum: int = 0):
if not isinstance(values, list) or not minimum <= len(values) <= maximum:
raise GA4Error(f": entre et champs.")
if any(not isinstance(v, str) or not re.fullmatch(FIELD_PATTERN, v) for v in values):
raise GA4Error(f": nom de champ invalide. Consulter ga4_metadata.")
if len(set(values)) != len(values):
raise GA4Error(f": champs repetes.")
def _body(start_date, end_date, dimensions, metrics, filters, limit, offset, order_by, descending):
first, last = _date_key(start_date), _date_key(end_date)
if first[0] == last[0] and first[1] > last[1]:
raise GA4Error("La date de debut doit preceder ou egaler la date de fin.")
_fields(dimensions, 9, "Dimensions")
_fields(metrics, 10, "Metriques", 1)
if set(dimensions) & set(metrics):
raise GA4Error("Un champ ne peut pas etre demande a la fois comme dimension et metrique.")
if type(limit) is not int or not 1 <= limit <= 2000:
raise GA4Error("limit doit etre compris entre 1 et 2000.")
if type(offset) is not int or not 0 <= offset <= 1000000:
raise GA4Error("offset doit etre compris entre 0 et 1000000.")
if not dimensions and offset != 0:
raise GA4Error("Pour un total sans dimensions, offset doit etre 0.")
if type(descending) is not bool:
raise GA4Error("descending doit etre un booleen.")
if len(filters) > 10:
raise GA4Error("Dix filtres au maximum, combines par ET.")
sort_field = metrics[0] if order_by is None else order_by
if sort_field not in dimensions + metrics:
raise GA4Error("order_by doit etre une dimension ou metrique demandee.")
order = (
if sort_field in dimensions else )
order["desc"] = descending
# Departager les egalites pour assurer la continuite entre pages d'un rapport stable.
orders = [order] + [
for d in dimensions if d != sort_field]
body =
if filters:
expressions = []
for f in filters:
expression =
expressions.append( if f.negate else expression)
body["dimensionFilter"] =
return body
def _rows(raw_rows, dim_headers, metric_headers):
output = []
for raw in raw_rows:
dim_values, metric_values = raw.get("dimensionValues", []), raw.get("metricValues", [])
if len(dim_values) != len(dim_headers) or len(metric_values) != len(metric_headers):
raise GA4Error("Colonnes de la reponse Google incoherentes.")
row =
for header, v in zip(metric_headers, metric_values):
value = v.get("value", "")
try:
number = int(value) if header.get("type") == "TYPE_INTEGER" else float(value)
if isinstance(number, float) and not math.isfinite(number):
raise ValueError()
except (ValueError, TypeError, OverflowError):
raise GA4Error("Valeur numerique Google inattendue; aucune conversion en zero.") from None
row[header["name"]] = number
output.append(row)
return output
mcp = FastMCP("GA4 personnel", log_level="WARNING", instructions=(
"Lecture seule de la propriete configuree dans PROPERTY_ID. ga4_status ne teste pas Google: utiliser ga4_check_access. "
"ga4_report avec dimensions=[] donne les totaux directs de Google. Ne pas sommer les utilisateurs uniques ni les taux entre lignes ou dates. "
"Consulter ga4_metadata pour les noms et descriptions des champs. Dates inclusives dans le fuseau metadata.timeZone de GA4; "
"NdaysAgo/yesterday/today sont calcules par Google dans ce fuseau. Preferer une fin a 3daysAgo pour reduire les donnees recentes provisoires, sans garantie de finalisation. "
"Les taux sont des fractions (0.25=25%); les durees sont selon le type, generalement secondes; devise dans metadata.currencyCode. "
"Verifier has_more et next_offset, metadata.subjectToThresholding, dataLossFromOtherRow, samplingMetadatas, emptyReason et schemaRestrictionResponse. "
"Une reponse vide ou l'absence de purchase ne prouve pas l'absence de ventes: le marquage et le consentement limitent les donnees. "
"sessionSourceMedium et sessionDefaultChannelGroup concernent l'acquisition des sessions; firstUserSourceMedium concerne la premiere acquisition. "
"Les clics GSC/Ads, sessions GA4, evenements cles GA4 et conversions Ads ne sont pas interchangeables. Aucun outil ne modifie GA4 ou le site."
))
READ_ONLY = ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=True)
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False))
def ga4_status() -> dict:
"""Verifie la passerelle locale sans contacter Google. Ne prouve pas l'acces GA4."""
return
@mcp.tool(annotations=READ_ONLY)
def ga4_report(
start_date: str = "30daysAgo", end_date: str = "3daysAgo",
dimensions: list[str] | None = None, metrics: list[str] | None = None,
filters: list[DimensionFilter] | None = None, limit: int = 100, offset: int = 0,
order_by: str | None = None, descending: bool = True,
) -> dict:
"""Lit un rapport GA4: totaux, trafic, pages, acquisition, evenements et ventes mesurees.
Dates inclusives AAAA-MM-JJ ou NdaysAgo/yesterday/today, fuseau de la propriete.
Defaut: 28 jours de 30daysAgo a 3daysAgo, totalUsers/sessions/screenPageViews.
dimensions=[]: total direct. Dimensions usuelles: date, country, deviceCategory,
pagePath, landingPagePlusQueryString, sessionSourceMedium, sessionCampaignName,
sessionDefaultChannelGroup, eventName. Metriques: sessions, totalUsers, activeUsers,
screenPageViews, engagedSessions, engagementRate, eventCount, keyEvents,
ecommercePurchases, purchaseRevenue (selon marquage et droits).
Filtres ET: [].
negate inverse un filtre. Les champs doivent etre compatibles selon Google.
limit 1..2000, offset 0..1000000. Paginer avec next_offset et les memes parametres.
Tri: premiere metrique decroissante par defaut; pour une serie, order_by='date', descending=False.
Les taux restent des fractions, les totaux sont fournis par Google, pas calcules par somme.
"""
dims = [] if dimensions is None else dimensions
mets = ["totalUsers", "sessions", "screenPageViews"] if metrics is None else metrics
fs = list(filters or [])
body = _body(start_date, end_date, dims, mets, fs, limit, offset, order_by, descending)
result = _read_google("report", body)
dh, mh = result.get("dimensionHeaders", []), result.get("metricHeaders", [])
if [h.get("name") for h in dh] != dims or [h.get("name") for h in mh] != mets:
raise GA4Error("Les colonnes Google ne correspondent pas aux champs demandes.")
rows = _rows(result.get("rows", []), dh, mh)
totals = _rows(result.get("totals", []), dh, mh)
total_rows = result.get("rowCount", len(rows))
has_more = bool(rows) and offset + len(rows) < total_rows
return
@mcp.tool(annotations=READ_ONLY)
def ga4_check_access() -> dict:
"""Teste l'acces reel par un rapport de 28 jours. Ne pretend pas lire le role attribue dans GA4."""
report = ga4_report()
return
@mcp.tool(annotations=READ_ONLY)
def ga4_metadata(search: str = "", kind: Literal["all", "dimensions", "metrics"] = "all",
limit: int = 50, offset: int = 0) -> dict:
"""Liste les noms API et descriptions des dimensions/metriques disponibles, y compris personnalisees.
search filtre le nom API, libelle et description (souvent en anglais, ex. purchase,
keyEvent, session, customEvent). Ceci ne liste pas les noms d'evenements observes:
utiliser ga4_report avec dimension eventName et metriques eventCount/keyEvents.
"""
if not isinstance(search, str) or len(search) > 200:
raise GA4Error("Recherche trop longue (200 caracteres au maximum).")
if kind not in :
raise GA4Error("kind invalide.")
if type(limit) is not int or not 1 <= limit <= 200 or type(offset) is not int or not 0 <= offset <= 100000:
raise GA4Error("Pagination invalide: limit 1..200 et offset 0..100000.")
result = _read_google("metadata")
fields = []
for group in ("dimensions", "metrics"):
if kind not in :
continue
for item in result.get(group, []):
searchable = " ".join(str(item.get(k, "")) for k in ("apiName", "uiName", "description"))
if search.casefold() in searchable.casefold():
fields.append()
fields.sort(key=lambda item: (item["kind"], item.get("apiName", "")))
page = fields[offset:offset + limit]
more = offset + len(page) < len(fields)
return
def test_access() -> int:
try:
result = ga4_check_access()
report = result["test_report"]
print("CONNEXION GA4 OK")
print("Propriete : " + PROPERTY_ID)
print("Autorisation technique : analytics.readonly")
print("Test reel : rapport Google accepte (le role GA4 n'est pas interroge)")
print("Periode : 28 jours, de J-30 a J-3 inclus, selon le fuseau GA4")
print("Fuseau GA4 : " + str(report["metadata"].get("timeZone", "non fourni")))
if report["rows"]:
row = report["rows"][0]
print(f"Utilisateurs : | Sessions : | Pages/ecrans vus : ")
else:
print("Lecture acceptee; aucune ligne. Ce resultat ne prouve pas une absence de trafic.")
return 0
except GA4Error as exc:
print("ECHEC DU TEST GA4 : " + str(exc), file=sys.stderr)
return 1
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--test-access", action="store_true")
args = parser.parse_args()
if args.test_access:
raise SystemExit(test_access())
mcp.run(transport="stdio")
Le serveur expose quatre outils : ga4_status pour vérifier sa réponse, ga4_check_access pour tester Google, ga4_report pour lire les rapports et ga4_metadata pour retrouver les noms des dimensions et métriques. Il ne contient aucune opération de modification de GA4.
Vérification du code
La connexion DOPHIS a été testée sur le PC puis depuis ChatGPT. L'adaptation générique présentée ici a également passé des tests hors ligne et un test du protocole MCP local. Le test réel avec votre propriété reste nécessaire : les droits de votre compte et vos données ne peuvent pas être validés à votre place.
5. Tester la lecture Google avant de créer le tunnel
Dans PowerShell, depuis le dossier de la passerelle, lancez :
.\venv\Scripts\python.exe .\ga4_server.py --test-access
Si l'accès fonctionne, la fenêtre affiche CONNEXION GA4 OK, votre ID de propriété, l'autorisation analytics.readonly, le fuseau GA4 et les chiffres du rapport. Ce test effectue une vraie lecture Google. Il ne se contente pas de constater qu'un programme démarre.
La période de contrôle couvre 28 jours, de J-30 à J-3 inclus, selon le fuseau de la propriété. Ce recul de trois jours limite les effets des données très récentes, sans garantir que Google ne les modifiera plus. Google explique les délais de traitement dans son aide sur la fraîcheur des données GA4.
En cas d'erreur 403, vérifiez l'activation de la Data API dans le projet du compte de service et son accès à la bonne propriété. Corrigez ce point avant de passer au tunnel. Une réponse acceptée sans aucune ligne confirme l'accès, mais elle ne prouve pas que le site n'a reçu aucune visite.
6. Créer le tunnel privé OpenAI
Ouvrez la plateforme OpenAI, puis les paramètres Tunnels. Créez un tunnel nommé, par exemple, GA4 personnel. Associez-le à l'organisation et à l'espace ChatGPT qui doivent l'utiliser, puis conservez son identifiant tunnel_....
Pour reproduire notre installation avec plusieurs passerelles, utilisez un tunnel distinct pour GA4. Vérifiez les droits : Tunnels Read + Manage pour le créer et Tunnels Read + Use pour l'utiliser. La documentation des tunnels MCP privés décrit ces associations et permissions.
Préparez une clé d'exécution OpenAI autorisée à utiliser ce tunnel. Si vous avez déjà une clé adaptée pour une autre passerelle, elle peut être réutilisée selon ses droits. Cette clé OpenAI et le fichier JSON Google ont deux rôles distincts.
Téléchargez le client Windows adapté à votre ordinateur depuis les versions officielles de tunnel-client. Extrayez l'exécutable, placez-le dans C:\Connecteur_IA\GA4 et nommez-le tunnel-client-ga4.exe. Dans notre installation, une copie du client déjà utilisé pour les autres passerelles a été employée.
7. Lancer le tunnel et ajouter le connecteur dans ChatGPT
Créez un fichier lancer-ga4.ps1 dans le même dossier et copiez-y ce lanceur. Il vous demande l'identifiant du tunnel et la clé OpenAI en saisie masquée. Cette version générique ne les enregistre pas : vous les renseignez à chaque lancement.
Afficher le code de lancer-ga4.ps1
#requires -Version 5.1
Set-StrictMode -Version 2.0
$ErrorActionPreference = 'Stop'
$secureKey = $null
$plainKey = $null
try
catch
finally
[void](Read-Host 'Entree pour fermer')
Lancez-le dans un processus PowerShell dédié :
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File 'C:\Connecteur_IA\GA4\lancer-ga4.ps1'
L'option ExecutionPolicy Bypass s'applique à ce processus. Le lanceur ne change pas la stratégie globale de Windows. Les options de connexion utilisées sont décrites dans la configuration officielle de tunnel-client.
Gardez la fenêtre ouverte. Sur ce PC, l'adresse http://127.0.0.1:63720/ui permet de consulter l'état du tunnel. Ce port doit être libre et ne doit pas déjà être utilisé par un autre lanceur.
Dans ChatGPT sur le Web, ouvrez Plugins / Applications → + → Ajouter un serveur MCP personnalisé, puis renseignez les champs suivants :
| Champ | Valeur pour cet exemple |
|---|---|
| Nom | GA4 personnel |
| Description | Lecture seule des rapports Google Analytics 4 de mon site |
| Connexion | Tunnel |
| Tunnel | Le tunnel GA4 créé à l'étape précédente |
| Authentification du serveur MCP | Aucune dans ce montage local via le tunnel authentifié |
Le choix « Aucune » concerne l'authentification du serveur MCP local. Le tunnel reste authentifié auprès d'OpenAI et le programme s'authentifie auprès de Google avec le compte de service. N'appliquez pas ce réglage à un serveur public exposant des données privées.
Terminez la création, installez ou activez le plugin si l'interface le demande, puis sélectionnez-le dans une conversation. Le guide d'ajout d'un serveur MCP personnalisé à ChatGPT présente cette procédure et la gestion des outils.
8. Vérifier la connexion depuis ChatGPT
Un tunnel connecté ne suffit pas à prouver que ChatGPT peut lire GA4. Faites un dernier test depuis la conversation :
Utilise le connecteur GA4 personnel et appelle ga4_check_access.
Donne les utilisateurs totaux, les sessions et les pages ou écrans vus
sur les 28 jours de J-30 à J-3 inclus.
Précise la propriété interrogée, le fuseau et les limites signalées par Google.
Comparez le résultat au test local, sur la même période et avec les mêmes métriques. Lors de notre installation, les chiffres lus depuis le PC puis depuis ChatGPT étaient identiques. C'est à ce stade que le raccordement complet a été validé.
| Contrôle | Ce qu'il démontre |
|---|---|
| Le serveur répond à ga4_status | Le programme MCP fonctionne |
| Le test local affiche CONNEXION GA4 OK | Le PC peut lire un rapport de la propriété Google |
| Le tunnel est prêt | Le transport entre le PC et OpenAI est disponible |
| ChatGPT appelle ga4_check_access et reçoit le rapport | La connexion fonctionne de bout en bout |
Exemples de demandes après la connexion
Précisez la période, l'indicateur et le découpage attendu. Pour les rapports de trafic, distinguez l'origine des sessions de la première acquisition d'un utilisateur.
Comprendre l'origine des visites
Utilise GA4 personnel. Sur les 28 jours de J-30 à J-3,
répartis les sessions par sessionSourceMedium.
Affiche aussi engagedSessions et engagementRate.
Signale les limites de données et convertis le taux en pourcentage pour la présentation.
Examiner les pages d'entrée
Sur la même période, donne les 20 premières pages d'entrée
avec landingPagePlusQueryString, sessions et engagedSessions.
Trie par sessions décroissantes et indique si d'autres lignes sont disponibles.
Contrôler les événements et les achats mesurés
Liste les événements enregistrés sur la période avec eventName,
eventCount et keyEvents. Vérifie la présence de purchase et des événements
de formulaire sans inventer leur nom. Si un événement attendu est absent,
distingue une absence de mesure d'une absence d'activité réelle.
Les noms ci-dessus correspondent aux champs de la Data API. L'outil ga4_metadata permet d'en retrouver la description et de repérer les champs personnalisés. Google peut refuser une combinaison incompatible de dimensions et de métriques ; il faut alors simplifier le rapport.
Quelles limites garder en tête pour analyser les résultats ?
La connexion ne répare pas le suivi GA4
Si votre site n'envoie pas correctement les événements d'achat ou de formulaire, ChatGPT ne les retrouvera pas dans les rapports. Le consentement, les bloqueurs et le paramétrage de la collecte peuvent également limiter les données disponibles. Une absence d'achat mesuré doit être rapprochée des commandes réelles de la boutique.
Les indicateurs des outils Google ne sont pas équivalents
Un clic Google Ads, un clic Search Console et une session GA4 ne mesurent pas la même étape. De même, un événement clé GA4 et une conversion Google Ads peuvent suivre des règles différentes. Avant de comparer les chiffres, alignez les dates, les fuseaux, les filtres et la définition des indicateurs.
Les utilisateurs et les taux ne se totalisent pas par addition
Un même utilisateur peut consulter plusieurs pages ou revenir plusieurs jours. Additionner les utilisateurs de chaque ligne risque donc de le compter plusieurs fois. Pour les totaux, demandez un rapport sans dimension. Le serveur conserve aussi les taux sous leur forme native : 0.25 correspond à 25 %.
La devise et les indications de qualité doivent être vérifiées
Pour les revenus, contrôlez la devise renvoyée dans metadata.currencyCode. Ne supposez pas qu'elle est l'euro parce que le site est français. Vérifiez également le fuseau metadata.timeZone, les éventuels seuils, l'échantillonnage et les lignes regroupées dans « (other) ».
La passerelle conserve les métadonnées de qualité des rapports GA4 ainsi que les informations de quota. Les limites doivent accompagner les conclusions lorsque Google les signale.
La même discipline de contrôle s'applique aux calculs proposés par une IA : notre guide pour créer et vérifier une formule Excel avec ChatGPT montre comment confronter une réponse au résultat attendu.
Que faire si la connexion ne fonctionne pas ?
| Message ou situation | Point à vérifier |
|---|---|
| Fichier Google absent | Le fichier google-service-account.json doit être à côté de ga4_server.py |
| VOTRE_ID_GA4 apparaît dans une erreur | Renseigner l'ID numérique dans la constante PROPERTY_ID du fichier Python |
| Google HTTP 403 | API activée dans le bon projet et compte de service Lecteur sur la bonne propriété |
| Google HTTP 400 | Dates, noms des champs, filtres et compatibilité des dimensions et métriques |
| Google HTTP 429 | Quota atteint : attendre et réduire la complexité des requêtes |
| Le tunnel n'apparaît pas dans ChatGPT | Association au bon espace ChatGPT et droits Tunnels Read + Use |
| La clé du tunnel est refusée | Clé d'exécution autorisée pour ce tunnel, organisation correcte et validité de la clé |
| Le connecteur fonctionnait puis ne répond plus | PC allumé, connexion Internet, sortie de veille et fenêtre du tunnel toujours ouverte |
Questions fréquentes sur la connexion de GA4 à ChatGPT
Faut-il payer un connecteur tiers ?
Non, la méthode présentée utilise une passerelle personnelle. Elle ne nécessite pas d'abonnement à un service tiers de connexion GA4. Vous devez néanmoins disposer des fonctionnalités et permissions nécessaires dans ChatGPT et OpenAI, et respecter les quotas Google.
Peut-on réutiliser le compte de service créé pour Search Console ?
Oui, si vous maîtrisez déjà ce compte et sa clé. Il faut activer la Google Analytics Data API dans le projet correspondant et ajouter son adresse comme Lecteur dans la propriété GA4. Les droits Search Console ne donnent pas automatiquement des droits Analytics.
ChatGPT peut-il modifier mes événements ou mes paramètres GA4 ?
Cette passerelle ne le permet pas. Elle demande le scope analytics.readonly et n'expose que la lecture de rapports et de métadonnées. Le rôle Lecteur dans GA4 complète cette limitation. La mention « lecture seule » dans le nom d'un connecteur ne suffirait pas à elle seule.
Faut-il laisser l'ordinateur allumé ?
Oui. Avec cette installation locale, le PC doit rester allumé, connecté et hors veille, avec le client de tunnel en fonctionnement. Pour rendre la connexion disponible en permanence, il faudrait héberger et maintenir la passerelle sur une machine adaptée.
La connexion permet-elle de retrouver les visites non suivies ?
Non. Elle donne accès aux rapports disponibles dans GA4. Elle ne reconstitue pas les visites ou événements qui n'ont pas été collectés. Le suivi du consentement et des achats doit être contrôlé séparément.
Peut-on analyser GA4, Search Console et Google Ads ensemble ?
Oui, lorsque chaque source est connectée et accessible dans la conversation. Il faut demander les périodes et les définitions utilisées pour chaque rapport, puis expliquer les écarts. Les chiffres ne doivent pas être assimilés ou additionnés sans vérifier ce qu'ils mesurent.
Comment couper l'accès ?
Fermer le lanceur arrête la disponibilité de cette passerelle locale. Pour retirer durablement l'accès aux données, supprimez le compte de service de la propriété GA4. Vous pouvez aussi désactiver le tunnel ou retirer le plugin de ChatGPT. Si une clé est partagée entre plusieurs connexions, sa suppression peut arrêter toutes celles qui l'utilisent.
Structurer l'usage de l'IA autour de vos données
Pour un usage régulier, définissez d'abord les questions utiles : origine des demandes, performance des pages ou suivi des ventes. La connexion fournit les données ; la qualité de la collecte et des règles de calcul reste déterminante pour leur interprétation.
Si ces analyses doivent ensuite alimenter vos fichiers de suivi Excel ou vos outils métier, nous pouvons échanger sur votre organisation et vos besoins.

