[{"data":1,"prerenderedAt":422},["ShallowReactive",2],{"blog-es-google-api-key-exposed-in-frontend":3},{"id":4,"title":5,"body":6,"category":380,"cover":381,"coverAlt":381,"description":382,"draft":383,"extension":384,"faq":385,"image":401,"keywords":402,"meta":409,"navigation":410,"ogTitle":411,"path":412,"published":413,"seo":414,"stem":415,"tldr":416,"updated":413,"__hash__":421},"blog_es\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend.md","¿Es un problema una clave de API de Google en tu frontend?",{"type":7,"value":8,"toc":368},"minimark",[9,18,26,35,40,43,46,49,52,56,59,66,69,75,79,89,141,148,151,158,162,260,263,268,272,275,282,292,296,299,305,308,311,321,325,356],[10,11,12,13,17],"p",{},"Abre tu app en el navegador, mira el código fuente de la página y busca ",[14,15,16],"code",{},"AIza",".\nSi aparece una cadena de cuarenta caracteres, probablemente alguien ya te ha\ndicho que está «expuesta», y probablemente no te dijo qué hacer después.",[10,19,20,21,25],{},"Aquí está la parte que la mayoría de los consejos sobre esto se equivocan: ",[22,23,24],"strong",{},"una\nclave de API de Google en tu frontend no es el mismo tipo de problema que una\nclave secreta de Stripe en tu frontend, y el arreglo no consiste en esconderla.","\nTratar las dos igual lleva o bien a asustarse por tu mapa o, peor, a acostumbrarse\na encogerse de hombros ante la palabra «expuesta» justo antes del día en que\nimporta.",[10,27,28,29,34],{},"Entre el 12 y el 14 de agosto de 2026 pasamos las mismas nueve comprobaciones\nexternas a 30.998 apps en funcionamiento creadas con Lovable, Bolt, v0, Replit y\nBase44. En 1.142 de ellas apareció una clave de API de Google. En tres apareció\nuna clave secreta de Stripe. Los números completos están en\n",[30,31,33],"a",{"href":32},"\u002Fresearch\u002Fvibe-coded-app-security-2026","nuestro informe de escaneo",".",[36,37,39],"h2",{"id":38},"es-malo-que-mi-clave-de-api-de-google-esté-expuesta-en-el-frontend","¿Es malo que mi clave de API de Google esté expuesta en el frontend?",[10,41,42],{},"Casi nunca. Depende por completo de si la clave está restringida.",[10,44,45],{},"Una clave de API de Google no es una contraseña. Se parece más a un número de\ncuenta: le dice a Google qué proyecto facturar y de qué cuota descontar. Por sí\nsola no dice nada sobre quién hace la petición.",[10,47,48],{},"Por eso puede vivir en tu página. El mapa lo dibuja el navegador de tu visitante,\nasí que el navegador es quien tiene que enviar ese número de cuenta a Google. No\nexiste una versión de esto en la que el mapa cargue y el número quede oculto.",[10,50,51],{},"La protección viene de un segundo ajuste, guardado del lado de Google, que dice\ndesde qué sitios web puede usarse el número. Google lo llama restricción de\nreferente HTTP. Con él puesto, la clave impresa en tu página funciona en tu sitio\ny devuelve un error en cualquier otro.",[36,53,55],{"id":54},"por-qué-tu-app-envía-la-clave","Por qué tu app envía la clave",[10,57,58],{},"Porque la petición sale del navegador de tu visitante, no de tu servidor.",[10,60,61,62,65],{},"Cuando alguien carga una página con un mapa, ese navegador habla directamente con\n",[14,63,64],{},"maps.googleapis.com",". Tiene que decir a qué proyecto de Google pertenece la\npetición, y ese identificador tiene que estar en la página, porque la página es\ndesde donde se hace la petición.",[10,67,68],{},"Google lo sabe. Por eso la restricción existe como control aparte: el\nidentificador iba a ser público de todas formas, así que lo que decide quién\npuede usarlo vive en un sitio al que el público no llega.",[70,71],"diagram",{"alt":72,"caption":73,"src":74},"Dos filas. En la fila superior una restricción se interpone entre las peticiones y Google: una petición desde yourapp.com la atraviesa y llega a maps.googleapis.com, mientras que la misma clave enviada desde other.example se detiene en la restricción y queda marcada con una cruz. En la fila inferior la restricción está dibujada como una línea discontinua y ambas peticiones pasan, la del desconocido punteada en ámbar.","La clave es idéntica en las dos filas. La única diferencia es si tiene una restricción puesta.","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Frestricted-or-not-1600x820.png",[36,76,78],{"id":77},"cómo-restringir-una-clave-de-api-de-google","Cómo restringir una clave de API de Google",[10,80,81,82,88],{},"Es gratis, son unos cinco minutos y no necesitas tocar el código de tu app. En la\n",[30,83,87],{"href":84,"rel":85},"https:\u002F\u002Fconsole.cloud.google.com\u002F",[86],"nofollow","consola de Google Cloud",":",[90,91,92,100,110,129,138],"ol",{},[93,94,95,96,99],"li",{},"Ve a ",[22,97,98],{},"APIs y servicios → Credenciales"," y haz clic en la clave que\nencontraste.",[93,101,102,103,106,107,34],{},"En ",[22,104,105],{},"Restricciones de aplicación",", elige ",[22,108,109],{},"Sitios web",[93,111,112,113,116,117,120,121,124,125,128],{},"Añade tu dominio. Para un sitio en ",[14,114,115],{},"yourapp.com",", añade\n",[14,118,119],{},"https:\u002F\u002Fyourapp.com\u002F*",". Añade también tu dominio de vista previa o de\npruebas, si tienes uno, y acuérdate de la dirección ",[14,122,123],{},".lovable.app"," o\n",[14,126,127],{},".vercel.app"," en la que se publicó tu app antes de conectarle un dominio\npropio.",[93,130,102,131,106,134,137],{},[22,132,133],{},"Restricciones de API",[22,135,136],{},"Restringir clave"," y marca solo las APIs\nque tu app llama de verdad. Un mapa con búsqueda de lugares necesita la API de\nJavaScript de Maps y la API de Places, y nada más.",[93,139,140],{},"Guarda, espera unos minutos, luego carga tu propio sitio y comprueba que el\nmapa se sigue dibujando.",[10,142,143,144,147],{},"Si el paso 3 está mal, te enteras al momento y a la vista: el mapa falla con\n",[14,145,146],{},"RefererNotAllowedMapError"," en la consola del navegador, que nombra el problema\nexacto. Añade el dominio que falta y vuelve a funcionar. Es un cambio reversible,\ny por eso merece la pena hacerlo antes de terminar de leer sobre él.",[10,149,150],{},"Una cosa que no hay que hacer: la propia guía de resolución de problemas de\nGoogle dice que las restricciones por dirección IP son para claves de servidor y\nno sirven para una clave que usa un navegador. Si restringes por IP una clave del\nfrontend, tu app se rompe para todos los visitantes.",[10,152,153,154,34],{},"Si prefieres ver qué claves está enviando tu app antes de ir una por una, nuestro\nescaneo gratuito lee tu sitio en vivo desde fuera y te dice lo que encuentra.\nTarda unos 20 segundos y no necesita cuenta: ",[30,155,157],{"href":156},"\u002F#scan","escanea tu app",[36,159,161],{"id":160},"qué-credenciales-de-google-van-en-un-navegador","Qué credenciales de Google van en un navegador",[163,164,165,184],"table",{},[166,167,168],"thead",{},[169,170,171,175,178,181],"tr",{},[172,173,174],"th",{},"Credencial",[172,176,177],{},"Qué aspecto tiene",[172,179,180],{},"¿En tu frontend?",[172,182,183],{},"Qué la protege de verdad",[185,186,187,208,224,242],"tbody",{},[169,188,189,193,198,205],{},[190,191,192],"td",{},"Clave de navegador de Maps o Places",[190,194,195],{},[14,196,197],{},"AIza…",[190,199,200],{},[201,202,204],"key-verdict",{"type":203},"safe","Va aquí",[190,206,207],{},"La restricción de referente, más un tope de cuota",[169,209,210,213,217,221],{},[190,211,212],{},"Clave de configuración web de Firebase",[190,214,215],{},[14,216,197],{},[190,218,219],{},[201,220,204],{"type":203},[190,222,223],{},"Las reglas de seguridad de Firebase y App Check",[169,225,226,229,233,239],{},[190,227,228],{},"Una clave que usas desde tu servidor",[190,230,231],{},[14,232,197],{},[190,234,235],{},[201,236,238],{"type":237},"danger","Nunca",[190,240,241],{},"Nada, una vez es pública. Déjala en el servidor",[169,243,244,247,253,257],{},[190,245,246],{},"Cuenta de servicio",[190,248,249,250],{},"un archivo JSON que contiene ",[14,251,252],{},"\"private_key\"",[190,254,255],{},[201,256,238],{"type":237},[190,258,259],{},"Nada. Esto sí son credenciales reales",[10,261,262],{},"Las tres primeras filas son la misma cadena. Una clave de API de Google no lleva\nescrito por delante para qué sirve, así que la pregunta nunca es «qué aspecto\ntiene esta clave» sino «qué puede hacer esta clave», y esa respuesta vive en la\nconsola y no en tu código.",[70,264],{"alt":265,"caption":266,"src":267},"Una sola clave AIza arriba se ramifica en tres copias idénticas. La primera está marcada con un visto y etiquetada yourapp.com, la segunda está marcada con un visto y etiquetada firebaseConfig, y la tercera está tachada y etiquetada con un asterisco que representa cualquier sitio web. Separado debajo por una línea discontinua, un cuarto elemento que dice type service_account está tachado.","Tres de estas son los mismos cuarenta caracteres. Lo que las separa es un ajuste que no se ve en el código de la página.","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fone-shape-three-jobs-1600x720.png",[36,269,271],{"id":270},"la-clave-de-firebase-está-pensada-para-ser-pública","La clave de Firebase está pensada para ser pública",[10,273,274],{},"Esta es la fila por la que más preguntan, y la propia documentación de Firebase\nla responde con claridad: las claves de API de los servicios de Firebase pueden\nir en el código o en archivos de configuración, porque no controlan el acceso a\nnada. De eso deciden las reglas de seguridad de Firebase y App Check.",[10,276,277,278,34],{},"Si te suena, es el mismo arreglo que usa Supabase. La clave publicable identifica\nel proyecto, y las reglas que hay detrás deciden fila por fila quién puede leer\nqué. En ambos casos la clave es segura solo gracias a esas reglas, así que las\nreglas son lo que hay que ir a mirar:\n",[30,279,281],{"href":280},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","activarlas no es lo mismo que estar protegido",[283,284,286],"callout",{"type":285},"warn",[10,287,288,291],{},[22,289,290],{},"La única trampa de Firebase, y es nueva."," La documentación de Firebase es\nconcreta al respecto: no añadas la API de Gemini para desarrolladores, listada\ncomo Generative Language API, a la lista de APIs permitidas de tu clave web de\nFirebase. Esa clave se publica a propósito, y cada llamada al modelo hecha con\nella se factura a tu proyecto. Es un error fácil de cometer en una app que empezó\nsiendo una app de Firebase y luego ganó una función de IA, que a estas alturas\nson muchísimas.",[36,293,295],{"id":294},"qué-pasa-de-verdad-cuando-se-filtra-una-clave-sin-restringir","Qué pasa de verdad cuando se filtra una clave sin restringir",[10,297,298],{},"Una factura, una caída o las dos. No una fuga de datos.",[10,300,301,302,304],{},"Los rastreadores automáticos recorren páginas públicas recogiendo cadenas ",[14,303,16],{},",\ny una clave sin restringir funciona desde cualquier sitio, así que la tuya acaba\nsirviendo teselas de mapa y búsquedas de lugares para el proyecto de otro. Google\nlo dice directamente en su propia documentación de primeros pasos: la razón para\nponer restricciones es evitar el robo de cuota.",[10,306,307],{},"Normalmente te enteras de una de dos maneras. La factura es mayor que la del mes\npasado sin un motivo que puedas señalar, o los mapas de tu app dejan de dibujarse\na mitad de mes porque el proyecto ha agotado su cuota y ahora cada visitante ve\nun rectángulo gris.",[10,309,310],{},"Ambas cosas tienen arreglo. Ninguna expone los datos de tus usuarios, porque una\nclave de Maps no puede leer tu base de datos. Esa es la diferencia honesta entre\neste hallazgo y una clave de base de datos filtrada, y es la razón por la que\nnuestro escáner reporta una clave de API de Google como algo que revisar y no\ncomo una emergencia.",[10,312,313,314,317,318,320],{},"La única credencial de Google que sí se comporta como una emergencia es una\ncuenta de servicio. Si tu app está enviando un archivo JSON con\n",[14,315,316],{},"\"type\": \"service_account\""," y un bloque ",[14,319,252],{}," dentro, eso son\ncredenciales reales con permisos reales sobre tu proyecto en la nube. Borra la\nclave en la consola y luego mira a qué podía llegar.",[36,322,324],{"id":323},"qué-hacer-ahora-mismo","Qué hacer ahora mismo",[326,327,328],"key-takeaways",{},[329,330,331,337,343,346,349],"ul",{},[93,332,333,334,336],{},"Busca ",[14,335,16],{}," en el código fuente de tu sitio en vivo. Cada coincidencia es una clave de la que responder.",[93,338,339,340,342],{},"Restringe cada una en la consola de Google Cloud: ",[22,341,109],{}," en las restricciones de aplicación, tu dominio, y solo las APIs que usas. Gratis, unos cinco minutos, sin tocar código.",[93,344,345],{},"Ponle también un tope de cuota diaria a la clave mientras estás ahí. La restricción reduce el tráfico; un tope limita lo que todo eso puede costar.",[93,347,348],{},"Deja tu clave de configuración de Firebase donde está. Comprueba en su lugar que tus reglas de seguridad están haciendo el trabajo, y mantén la API de Gemini fuera de la lista de permitidas de esa clave.",[93,350,351,352,355],{},"Si encuentras un archivo JSON de ",[14,353,354],{},"service_account"," en tu frontend, trátalo como urgente. Borra la clave en la consola en vez de solo quitar el archivo, porque tu historial de versiones sigue teniendo el valor antiguo.",[10,357,358,359,363,364,34],{},"Si prefieres trabajar esto como una lista, la\n",[30,360,362],{"href":361},"\u002Fchecklist","lista de seguridad de 10 minutos"," cubre esto junto con las otras\ncosas que conviene desactivar en una app recién lanzada. Y para la pregunta más\namplia de qué claves van en un navegador, tenemos\n",[30,365,367],{"href":366},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","una guía para distinguir las claves publicables de las secretas",{"title":369,"searchDepth":370,"depth":370,"links":371},"",3,[372,374,375,376,377,378,379],{"id":38,"depth":373,"text":39},2,{"id":54,"depth":373,"text":55},{"id":77,"depth":373,"text":78},{"id":160,"depth":373,"text":161},{"id":270,"depth":373,"text":271},{"id":294,"depth":373,"text":295},{"id":323,"depth":373,"text":324},"Fundamentos de seguridad",null,"Una clave de API de Google en tu frontend es la clave que más encuentra nuestro escáner, y casi siempre no pasa nada. Un ajuste gratuito decide cuál es cuál.",false,"md",[386,389,392,395,398],{"q":387,"a":388},"Alguien encontró mi clave de Google Maps en el código de la página. ¿Debo rotarla?","Restríngela primero: lleva unos cinco minutos y no rompe nada. Abre la clave en la consola de Google Cloud, pon las restricciones de aplicación en Sitios web y añade tu dominio, y después limita las restricciones de API a las APIs que usa tu app. Rotarla viene después, y solo si la clave estuvo sin restringir un tiempo y ves consumo que no has provocado tú.",{"q":390,"a":391},"¿No puedo esconder la clave para que nadie la encuentre?","No. El navegador de tu visitante tiene que enviar la clave a Google para cargar el mapa, así que todo lo que el navegador puede usar, un visitante puede leerlo. Minificar o renombrar solo frena a alguien unos segundos. Restringir la clave es el arreglo que sí funciona, y funciona tanto si alguien encuentra la clave como si no.",{"q":393,"a":394},"Mi clave está restringida a mi dominio. ¿Puede usarla alguien igualmente?","Una cabecera de referente se puede falsificar, así que alguien decidido puede enviar peticiones que digan venir de tu sitio. Lo que la restricción elimina es el caso fácil: un rastreador automático que recoge claves en páginas públicas y las usa directamente desde su propio servidor. Ese es el tráfico que produce facturas sorpresa, así que la restricción merece la pena aunque no sea un muro. Ponle además un tope de cuota diaria a la clave y tendrás un techo para lo que todo esto pueda costarte.",{"q":396,"a":397},"Firebase puso una clave de API en mi archivo de configuración. ¿Es un error?","No, y Firebase lo documenta. Una clave de API web de Firebase identifica tu proyecto en vez de autorizar el acceso, y del acceso deciden las reglas de seguridad de Firebase y App Check. Está pensada para estar en tu código. Lo único que hay que evitar es añadir la API de Gemini para desarrolladores a la lista de APIs permitidas de esa clave, porque eso convierte una clave que publicas a propósito en una que puede gastar dinero.",{"q":399,"a":400},"¿Y si encuentro un archivo con \"type\": \"service_account\" en mi app?","Esa es otra situación y es urgente. Una clave de cuenta de servicio son credenciales reales con una clave privada dentro y su sitio es un servidor. Borra la clave en la consola de Google Cloud, en IAM y administración y luego Cuentas de servicio, saca el archivo de tu frontend y revisa tu facturación y tus registros de auditoría. Borrarla solo del código no cierra la puerta, porque el valor antiguo sigue en tu historial de versiones.","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",[403,404,405,406,407,408],"clave api de google en el frontend","restringir clave api de google maps","restricción de referente http","clave api de firebase pública","clave api AIza","es segura mi clave api de google",{},true,"¿Una clave de API de Google en tu frontend?","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","2026-08-22",{"title":5,"description":382},"blog\u002Fgoogle-api-key-exposed-in-frontend",[417,418,419,420],"Una clave de API de Google expuesta en tu frontend casi siempre está bien, porque una clave de Google es un identificador de facturación y no una contraseña.","Lo que la hace segura es una restricción de referente HTTP: un ajuste que le dice a Google que la clave solo funciona desde tu propio sitio web.","Es gratis, lleva unos cinco minutos y es lo único que merece la pena hacer hoy.","Un archivo de cuenta de servicio de Google en tu app es el caso distinto y urgente. Eso sí son credenciales reales.","32u0BoP018InzSKHE5jFv_KEeyn-p_a_RXss2rt4kro",1787826048205]