Infrastructure
· 17 checks — DNS, redirects, IPv6, crawlability, URL variants, and domain intelligence rolled into one auditable list.DCDN & DeliveryActionNo CDN detectedFIX
Consider using a CDN to improve global delivery speed and reduce origin load.
BDNSSECUnsigned (DNSSEC not deployed)REVIEW
BCAA RecordsNo CAA records (any CA may issue certificates)REVIEW
CReverse DNSAction0/16 IPs match cert SANREVIEW
CCrawlabilityActionrobots.txt present, sitemap with 0 URLsREVIEW
Search engines may not be able to parse the sitemap. Fix XML validation errors.
An unparseable sitemap is silently ignored by Google — the URLs it advertises are never queued for crawl.
Learn more ▾ ▴
Google's sitemap parser is strict about XML validity. A single unescaped `&` or unclosed tag invalidates the whole file. Run your sitemap through a validator (Search Console's Sitemaps report flags it) and fix the offending entry. Most generators escape correctly; mistakes usually come from manually-written entries.
Source: sitemaps.org / Google Search Central
An empty sitemap provides no value. Add <url> entries for your pages.
An empty sitemap signals 'no content to index' to Google — actively harmful versus having no sitemap at all.
Learn more ▾ ▴
Google compares URLs in the sitemap against URLs it has crawled. An empty sitemap on a site with thousands of pages signals abandonment. Either populate it correctly (most CMSes auto-generate) or delete the file and let Google crawl normally.
Source: Google Search Central / sitemaps.org
Add a 'Sitemap:' directive to robots.txt so search engines can discover your sitemap.
robots.txt omits Sitemap: directive — crawlers must fetch /sitemap.xml by convention; reliable but missing the explicit hint.
Source: sitemaps.org
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<title>Cookie check</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<style>
:root {
color-scheme: light dark;
}
body {
font-family: 'Inter', Helvetica, Arial, sans-serif;
background: light-dark(#F8F8F7, #191919);
color: light-dark(#1f1f1f, #e3e3e3);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
min-height: 100vh;
margin: 0;
padding: 20px;
text-align: center;
}
.container {
background: light-dark(#FFFFFF, #1F1F1F);
padding: 32px;
border-radius: 16px;
border: 1px solid light-dark(#E2E3E4, #3E3E3E);
max-width: min(80%, 500px);
width: 100%;
color: light-dark(#2B2D31, #D4D4D4);
}
h1 {
font-size: 20px;
font-weight: 500;
margin-top: 1rem;
margin-bottom: 1rem;
color: light-dark(#2B2D31, #D4D4D4);
}
p {
font-size: 14px;
color: light-dark(#2B2D31, #D4D4D4);
line-height: 21px;
margin: 0 0 1.5rem 0;
}
.icon {
margin-bottom: 1rem;
line-height: 0;
}
.button-container {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 2rem;
}
button {
background-color: light-dark(#fff, #323232);
color: light-dark(#2B2D31, #FCFCFC);
border: 1px solid light-dark(#E2E3E4, #3E3E3E);
border-radius: 12px;
padding: 8px 12px;
font-size: 14px;
line-height: 21px;
cursor: pointer;
transition: background-color 0.2s;
font-weight: 400;
font-family: 'Inter', Helvetica, Arial, sans-serif;
width: 100%;
}
button:hover {
background-color: light-dark(#EAEAEB, #424242);
}
.hidden {
display: none;
}
/* Loading Spinner Animation */
.spinner {
margin: 0 auto 1.5rem auto;
width: 40px;
height: 40px;
border: 4px solid light-dark(#f0f0f0, #262626);
border-top: 4px solid light-dark(#076eff, #87a9ff); /* Blue color */
border-radius: 50%;
animation: spin 1s linear infinite;
}
.logo {
border-radius: 10px;
display: block;
margin: 0 auto 2rem auto;
}
.logo.hidden {
display: none;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div class="container">
<img
class="logo"
src="https://www.gstatic.com/aistudio/ai_studio_favicon_2_256x256.png"
alt="AI Studio Logo"
width="256"
height="256"
/>
<div class="spinner"></div>
<div id="error-ui" class="hidden">
<div class="icon">
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="48px"
height="48px"
fill="#D73A49"
>
<path
d="M12,2C6.486,2,2,6.486,2,12s4.486,10,10,10s10-4.486,10-10S17.514,2,12,2z M13,17h-2v-2h2V17z M13,13h-2V7h2V13z"
/>
</svg>
</div>
<div id="stepOne" class="text-container">
<h1>Action required to load your app</h1>
<p>
It looks like your browser is blocking a required security cookie, which is common on
older versions of iOS and Safari.
</p>
<div class="button-container">
<button id="authInSeparateWindowButton" onclick="redirectToReturnUrl(true)">Authenticate in new window</button>
</div>
</div>
<div id="stepTwo" class="text-container hidden">
<h1>Action required to load your app</h1>
<p>
It looks like your browser is blocking a required security cookie, which is common on
older versions of iOS and Safari.
</p>
<div class="button-container">
<button id="interactButton" onclick="redirectToReturnUrl(false)">Close and continue</button>
</div>
</div>
<div id="stepThree" class="text-container hidden">
<h1>Almost there!</h1>
<p>
Grant permission for the required security cookie below.
</p>
<div class="button-container">
<button id="grantPermissionButton" onclick="grantStorageAccess()">Grant permission</button>
</div>
</div>
</div>
</div>
<script>
const AUTH_FLOW_TEST_COOKIE_NAME = '__SECURE-aistudio_auth_flow_may_set_cookies';
const COOKIE_VALUE = 'true';
function getCookie(name) {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = cookies[i].trim();
if (cookie.startsWith(name + '=')) {
return cookie.substring(name.length + 1);
}
}
return null;
}
function setAuthFlowTestCookie() {
// Set the cookie's TTL to 1 minute. This is a short lived cookie because it is only used
// when the user does not have an auth token or their auth token needs to be reset.
// Making this cookie too long-lived allows the user to get into a state where they can't
// mint a new auth token.
document.cookie = `${AUTH_FLOW_TEST_COOKIE_NAME}=${COOKIE_VALUE}; Path=/; Secure; SameSite=None; Domain=${window.location.hostname}; Partitioned; Max-Age=60;`;
}
/**
* Returns true if the test cookie is set, false otherwise.
*/
function authFlowTestCookieIsSet() {
return getCookie(AUTH_FLOW_TEST_COOKIE_NAME) === COOKIE_VALUE;
}
/**
* Redirects to the return url. If autoClose is true, then the return url will be opened in a
* new window, and it will be closed automatically when the page loads.
* Options:
* storageAccessGranted: if true, appends __storage_access_granted=1 to
* the return url so the Lua auth script can set the test cookie
* server-side (needed for Safari/iOS where document.cookie is blocked).
*/
async function redirectToReturnUrl(autoClose, storageAccessGranted = false) {
const initialReturnUrlStr = new URLSearchParams(window.location.search).get('return_url');
const returnUrl = initialReturnUrlStr ? new URL(initialReturnUrlStr) : null;
// Prevent potentially malicious URLs from being used
if (returnUrl.protocol.toLowerCase() === 'javascript:') {
console.error('Potentially malicious return URL blocked');
return;
}
if (storageAccessGranted) {
returnUrl.searchParams.set('__storage_access_granted', '1');
}
if (autoClose) {
returnUrl.searchParams.set('__auto_close', '1');
const url = new URL(window.location.href);
url.searchParams.set('return_url', returnUrl.toString());
// Land on the cookie check page first, so the user can interact with it before proceeding
// to the return url where cookies can be set.
window.open(url.toString(), '_blank');
const hasAccess = await document.hasStorageAccess();
document.querySelector('#stepOne').classList.add('hidden');
if (!hasAccess) {
document.querySelector('#stepThree').classList.remove('hidden');
} else {
window.location.reload();
}
} else {
window.location.href = returnUrl.toString();
}
}
/**
* Grants the browser permission to set cookies. If successful, then it redirects to the
* return url.
*/
async function grantStorageAccess() {
try {
await document.requestStorageAccess();
// Recent Safari/iOS versions block document.cookie entirely in
// cross-site iframes, even after requestStorageAccess(). Only
// server-side Set-Cookie headers work. Signal to the Lua auth script
// via query param so it can set the test cookie server-side.
redirectToReturnUrl(false, /* storageAccessGranted= */ true);
} catch (err) {
console.log('error after button click: ', err);
}
}
/**
* Verifies that the browser can set cookies. If it can, then it redirects to the return url.
* If it can't, then it shows the error UI.
*/
function verifyCanSetCookies() {
setAuthFlowTestCookie();
if (authFlowTestCookieIsSet()) {
// Check if we are on the auto-close flow, and if so show the interact button.
const returnUrl = new URLSearchParams(window.location.search).get('return_url');
const autoClose = new URL(returnUrl).searchParams.has('__auto_close');
if (autoClose) {
document.querySelector('#stepOne').classList.add('hidden');
document.querySelector('#stepTwo').classList.remove('hidden');
} else {
redirectToReturnUrl(false);
return;
}
}
// The cookie could not be set, so initiate the recovery flow.
document.querySelector('.logo').classList.add('hidden');
document.querySelector('.spinner').classList.add('hidden');
document.querySelector('#error-ui').classList.remove('hidden');
}
// Start the cookie verification process.
verifyCanSetCookie
BTLS Certificate Expiry & Recommendations69 days until leaf cert expires — 3 issues to addressREVIEW
Certificate validity
Recommended actions
- Enable HSTS: Strict-Transport-Security: max-age=31536000; includeSubDomains
- Enable DNSSEC on your domain for DNS spoofing protection
- Enable OCSP stapling on your TLS server to remove a CA roundtrip and protect user privacy
BCDN Cache ObservabilityNo CDN cache-status headers in the responseREVIEW
BOperational Status PageNo status page link detectedREVIEW
ADNS Records8 A records, 25 ms lookupPASS
| A | 34.143.79.2, 34.143.77.2, 34.143.76.2, 34.143.72.2, 34.143.73.2, 34.143.75.2, 34.143.78.2, 34.143.74.2 |
| AAAA | 2600:1901:81d5:200::, 2600:1901:81d4:200::, 2600:1900:4240:200::, 2600:1900:4242:200::, 2600:1900:4243:200::, 2600:1900:4241:200::, 2600:1900:4245:200::, 2600:1900:4244:200:: |
| CNAME | — |
| NS | — |
| MX | — |
| TXT | — |
| CAA | Lookup not available with standard resolver |
SPF helps prevent email spoofing. Add a TXT record starting with 'v=spf1'.
Without SPF, receiving servers can't validate sending IPs — your domain is easier to spoof in phishing.
Learn more ▾ ▴
SPF complements DMARC. Both should be published. SPF records list authorized sending IPs (e.g., `v=spf1 include:_spf.google.com ~all` for Google Workspace). After publishing, verify in Google Postmaster Tools or mxtoolbox.
Source: RFC 7208 (SPF)
A+Subdomain TakeoverNo subdomain takeover risk detectedPASS
A+Multi-Resolver DNS SpeedMean 14ms across 3 resolvers (spread 21ms)PASS
ARedirect Chain1 redirect(s), 881 ms totalPASS
https://ais-pre-psgakquiwaol5aevbdjv6g-7...
315 ms · HTTP/1.1
https://ais-pre-psgakquiwaol5aevbdjv6g-7...
566 ms · HTTP/1.1 FINAL
| # | URL | Status | Time | Protocol | Server |
|---|---|---|---|---|---|
| 1 | https://ais-pre-psgakquiwaol5aevbdjv6g-7... | 302 | 315 ms | HTTP/1.1 | Google Frontend |
| 2 | https://ais-pre-psgakquiwaol5aevbdjv6g-7... | 200 | 566 ms | HTTP/1.1 | Google Frontend |
See the visual redirect chain in the HTTP Probe tab →
If permanent, use 301 instead.
302 (Found) is for genuinely temporary redirects — if this redirect is permanent, switch to 301 to preserve SEO equity.
Learn more ▾ ▴
Search engines treat 302 as temporary, keeping the original URL indexed and not transferring full link equity to the destination. Use 301 (Moved Permanently) for permanent redirects (HTTP→HTTPS, www-vs-non-www, URL restructures).
Source: Google Search Central
A+IPv6 ReadinessIPv6 reachable (17 ms)PASS
AURL Variantswww/non-www, trailing slash, HTTP→HTTPSPASS
www / non-www
HTTP → HTTPS
Use a permanent redirect (301 or 308) instead of a temporary one
AHTTP Probe TimingTotal 592 ms — DNS, TCP, TLS, TTFB, content transfer breakdownPASS
Connection waterfall
A+Health Check EndpointHealth endpoint at https://ais-pre-psgakquiwaol5aevbdjv6g-759203062707.asia-east1.run.app/health (HTTP 200)PASS
Domain IntelligenceDomain intelligence data not availableINFO
RDAP and WHOIS lookup both failed