La exportación de GA4 hacia BigQuery de Google Cloud tiene muchísimas ventajas, sin embargo, tenemos un límite de eventos diarios que poder exportar por propiedad:
Para las propiedades de GA4 no 360, el límite es de 1 millón (1M) de eventos diarios, mientras que para las 360 el límite es de miles de millones, por lo que podemos decir que es ilimitada.
Sin duda alguna, en muchas ocasiones nos encontramos con los límites en las propiedades estandar, y aqui vienen los problemas:

Efectivamente, GA4 nos notifica que hemos excedido el límite diario de exportación: prueba de ello la imagen anterior. Para solventar este límite, nos tocará ajustar los nombres de los eventos para decidir cuáles exportar y cuáles no.
Pero no estamos aquí para esto ahora. El objetivo de este artículo es aprovechar las herramientas de Google Cloud para recibir un email cuando el límite esté próximo para ir preparándonos.
Para ello haremos lo siguiente:
- Crearemos una función en Cloud Run para consultar el histórico de los últimos 7 días.
- Obtendremos los datos y comprobaremos si el límite ha sido alcanzado
- Enviaremos vía email el resultado si se cumplen los requisitos que marquemos.
- Programamos la función para que se ejecute cuando necesitemos.
Antes de nada, necesitaremos tener una contraseña de app de nuestra cuenta de Gmail que guardaremos en Secret Manager.
Creando secreto en Secret Manager
Nos vamos a Secret Manager y creamos el secreto de nuestra contreseña de app creada previamente.
Copiemos la ruta, la necesitaremos más adelante. El objetivo de esto es no definir nuestra contraseña -dato sensible- dentro de la función, sino declararlo como variable para que la función, con los permisos necesarios heredados de la cuenta de servicio que la ejecute, consultará.

Configurando la función Cloud en Cloud Run
Creamos una función Cloud Run con el script de Python con las comprobaciones de los últimos 7 días de eventos generados.
¿Qué hace la función? Llama al secreto, y lo obtiene para después consultar el histórico de los eventos recibidos y enviarlo en el email.
Comentamos sobre el código:
Seteamos el límite de eventos con el millón de eventos del límite para una propiedad normal de GA4:
LIMITE_EVENTOS = 1_000_000
Función nueva recogiendo los últimos 7 días de datos sin incluir hoy.
def enviar_eventos_diarios(request):
client = bigquery.Client()
QUERY = """
SELECT
event_date AS fecha,
COUNT(*) AS total_eventos
FROM
`projectid.table.events_*`
WHERE
_TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY))
AND FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
GROUP BY fecha
ORDER BY fecha DESC
"""
results = client.query(QUERY).result()
fechas = []
eventos = []
for row in results:
fechas.append(str(row.fecha))
eventos.append(row.total_eventos)
if not eventos:
return 'No se encontraron datos'
# Invertir para orden cronológico ascendente
fechas.reverse()
eventos.reverse()
Creamos el gráfico que se generará con los datos y que va adjunto al email.
# Crear gráfico con doble eje Y
fig, ax1 = plt.subplots(figsize=(8, 5))
ax1.bar(fechas, eventos, label="Eventos diarios", color='skyblue')
ax1.set_xlabel("Fecha")
ax1.set_ylabel("Eventos diarios", color='skyblue')
ax1.tick_params(axis='y', labelcolor='skyblue')
ax1.set_xticklabels(fechas, rotation=45)
ax2 = ax1.twinx()
ax2.axhline(y=LIMITE_EVENTOS, color='red', linestyle='--', label="Límite (1M)")
ax2.set_ylabel("Límite eventos", color='red')
ax2.tick_params(axis='y', labelcolor='red')
ax2.set_ylim(0, max(LIMITE_EVENTOS, max(eventos)*1.1))
# Combinar leyendas
lines_1, labels_1 = ax1.get_legend_handles_labels()
lines_2, labels_2 = ax2.get_legend_handles_labels()
ax1.legend(lines_1 + lines_2, labels_1 + labels_2, loc='upper left')
plt.title("Eventos diarios últimos 7 días")
plt.tight_layout()
img_bytes = io.BytesIO()
plt.savefig(img_bytes, format='png')
img_bytes.seek(0)
Llamamos al Secret Manager para recibir la password de la cuenta de Gmail emisora -ya guardado previamente-
# Obtener password de Secret Manager
secret_client = secretmanager.SecretManagerServiceClient()
secret_name = f"projects/projectid/secrets/secreto/versions/latest"
gmail_password = secret_client.access_secret_version(name=secret_name).payload.data.decode("UTF-8")
Cálculo de la métrica y montaje del email para enviarlo.
# Preparar datos para email
total_ultimo_dia = eventos[-1] # Último día tras invertir, es el más reciente
porcentaje = (total_ultimo_dia / LIMITE_EVENTOS) * 100
#Podemos ajustar el umbral
if porcentaje >= 90:
estado = "🚨 Límite de eventos alcanzado" if total_ultimo_dia >= LIMITE_EVENTOS else "⚠️ Aproximándose al límite"
# Construir email HTML con imagen inline
msg = MIMEMultipart('related')
msg['Subject'] = 'Google Cloud: límite de eventos diarios'
msg['From'] = 'email@gmail.com'
msg['To'] = 'email@gmail.com'
msg['Cc'] = 'emailencopia@perezgarcia.es'
html = f"""
<html>
<body>
<p>{estado}</p>
<p>Límite: {LIMITE_EVENTOS:,}</p>
<p>Porcentaje del límite (último día): {porcentaje:.2f}%</p>
<p>Eventos diarios últimos 7 días:</p>
<p>
El número de eventos diarios es: {total_ultimo_dia:,}<br>
</p><br>
<img src="cid:grafico" alt="Gráfico de eventos diarios"><br>
</body>
</html>
"""
msg.attach(MIMEText(html, 'html'))
image = MIMEImage(img_bytes.read())
image.add_header('Content-ID', '<grafico>')
msg.attach(image)
# Enviar email
smtp = smtplib.SMTP_SSL('smtp.gmail.com', 465)
smtp.login('joangpega@gmail.com', gmail_password)
smtp.sendmail(msg['From'], [msg['To'], msg['Cc']], msg.as_string())
smtp.quit()
return 'Email enviado correctamente'
else:
return f'No se envió email, porcentaje {porcentaje:.2f}% por debajo del umbral'
🔗 Te dejo por aquí el enlace al código python íntegro de la función Cloud en mi Github.
Resultado con el límite alcanzado

Este email ha sido creado de manera básica, pero podemos aportar mucha más información de la proporcionada. Todo esto es personalizable, incluso podremos aplicar predicción de eventos en base al histórico o coger como referencia una media de un periodo más amplio. Estoy trabajando en una versión mejorada del email con indicación de eventos superados, para saber qué evento ha sido el que ha generado la alerta.
Suscríbete a la newsletter
Y recibe un resumen mensual de todos los artículos publicados
🔗 Recuerda que puedes configurar los límites presupuestarios de Google Cloud con ayuda de este artículo: Control de presupuesto Cloud: crear una tabla de costes en BigQuery, y visualizarlas