nogales.health
Find a Doctor Specialties How It Works For Doctors
nogales.health

nogales.health · AI-assisted · Designed by Nogales.Digital · · ·
nogales.health · Designed by Nogales.Digital Studio · © 2025

About nogales.health

nogales.health is a bilingual, AI-powered health directory connecting cross-border patients with trusted doctors, dentists, and specialists in Nogales, Sonora, Mexico.

Nogales, Sonora sits just minutes from the Arizona border. Thousands of Americans visit each year for dental work, surgery, and specialist care — at a fraction of US costs.

This directory is a project of Nogales.Digital Studio, a local digital marketing agency serving health professionals in Nogales, Sonora.

Privacy Policy

Last updated: June 2025

What we collect

nogales.health does not require account creation or personal information to browse. Anonymous usage data is collected via Umami Analytics — a privacy-first, cookieless tool that does not track individuals.

AI conversations

Conversations are sent to Google's Gemini API. We do not store these on our servers. See Google's privacy policy.

Cookies

No tracking cookies. Your API key is stored only in your browser's session storage and never transmitted to our servers.

Contact

nogales.health@gmail.com

Terms of Use

Last updated: June 2025

Directory purpose

nogales.health is an informational directory only. We do not provide medical advice, diagnoses, or treatment recommendations. Always consult a qualified healthcare professional.

Listings accuracy

We make reasonable efforts to ensure accuracy but cannot guarantee all information is current. Contact providers directly to verify details before visiting.

AI assistant

The AI assistant is for general guidance only and is not a substitute for professional medical advice. We are not liable for decisions made based on AI-generated content.

Jurisdiction

Operated by Nogales.Digital Studio, Nogales, Sonora, Mexico. Use governed by applicable Mexican law.

============================= */ /* ===== SYSTEM PROMPTS ===== */ const SYS_EN = `You are the AI assistant for nogales.health, a health directory for Nogales, Sonora, Mexico. YOUR ROLE: Guide patients to real healthcare providers in Nogales through a short warm conversation. CONVERSATION FLOW: 1. Patient states a healthcare need 2. Ask ONE focused follow-up (e.g. "What kind of dental work do you need?") 3. Once you know their specific need, output ONLY a JSON block like this — no text before or after: \`\`\`json { "action": "show_results", "query": "specific need in plain english", "specialty": "Dentist / General Doctor / Bariatric Surgeon / etc.", "context_message": "Warm 1-sentence intro e.g. 'Here are the top-rated dentists for extractions in Nogales:'", "results": [ { "id": "unique-slug", "name": "Full provider or clinic name", "specialty": "Their specialty", "address": "Street, Nogales, Sonora", "phone": "number or null", "rating": 4.5, "review_count": 82, "review_snippet": "Short review summary", "hours": "Mon-Sat 9am-6pm or null", "services": ["Service 1", "Service 2", "Service 3"], "bio": "2-3 sentence description", "maps_url": "https://www.google.com/maps/search/?api=1&query=NAME+Nogales+Sonora", "whatsapp": "52631XXXXXXX or null", "premium": false } ] } \`\`\` RULES: - EXACTLY 3 results, highest rating first - Use REAL providers in Nogales, Sonora from your training data - If unsure of a detail, use null — never invent phone numbers or addresses - ratings: realistic range 3.8-4.9 - maps_url: always https://www.google.com/maps/search/?api=1&query=NAME+Nogales+Sonora (spaces as +) - For "list my practice" inquiries: reply normally (no JSON), explain tiers, direct to nogales.health@gmail.com NOGALES CONTEXT: Adjacent to Nogales, Arizona (DeConcini crossing). Most clinics in Centro, walkable. Many US-trained English-speaking doctors. Costs 50-80% less than US. Pay out of pocket.`; const SYS_ES = `Eres el asistente de IA de nogales.health, directorio de salud para Nogales, Sonora. FLUJO: Haz UNA pregunta de seguimiento para clarificar la necesidad del paciente. Luego responde SOLO con JSON: \`\`\`json { "action": "show_results", "query": "necesidad especifica", "specialty": "especialidad", "context_message": "Intro calida de 1 oracion", "results": [{"id":"slug","name":"Nombre","specialty":"Especialidad","address":"Direccion, Nogales, Sonora","phone":null,"rating":4.5,"review_count":80,"review_snippet":"Resumen resenas","hours":null,"services":["Servicio 1"],"bio":"Descripcion 2-3 oraciones","maps_url":"https://www.google.com/maps/search/?api=1&query=NOMBRE+Nogales+Sonora","whatsapp":null,"premium":false}] } \`\`\` REGLAS: 3 resultados reales de Nogales, Sonora. null para detalles desconocidos. No inventar contactos.`; /* ===== PREMIUM LISTINGS ===== */ const PREMIUM = [ { id:"the-tooth-inc", name:"The Tooth Inc.", specialty:"Cosmetic & General Dentistry", address:"Av. Alvaro Obregon 123, Centro, Nogales, Son.", phone:"631-555-0199", rating:4.9, review_count:147, review_snippet:"Best dental experience I've ever had. Dr. Chavez is meticulous and the staff incredibly welcoming.", hours:"Mon-Sat 8am-6pm", services:["Dental implants","Teeth whitening","Porcelain crowns","Full-mouth restorations","Cleanings & exams"], bio:"Expert cosmetic dentist with 15+ years specializing in cross-border patient care and full-mouth restorations. English-speaking staff. Same-day consultations available.", booking_link:"https://cal.com/the-tooth-inc/consultation", maps_url:"https://www.google.com/maps/search/?api=1&query=The+Tooth+Inc+Nogales+Sonora", whatsapp:"526315550199", premium:true, keywords:["dentist","dental","teeth","tooth","implant","crown","whitening","cleaning","cosmetic","extraction","root canal","odontolog","dentista","diente","implante","corona","blanqueamiento"] } ]; /* ===== STATE ===== */ let history=[], lang='en', started=false, lastResults=[], lastSpecialty=''; /* ===== LANGUAGE ===== */ const TYPED_Q={en:"How can we help you today?", es:"\xBFC\xF3mo podemos ayudarte hoy?"}; const PLACEHOLDERS={en:"Describe what you need...", es:"Describe lo que necesitas..."}; const L={ en:{about:"About",privacy:"Privacy",terms:"Terms",by:"Designed by",footBy:"Designed by",showMore:"Show more results",searching:"Searching...",moreOptions:"Here are more options:",whatsapp:"WhatsApp",call:"Call",map:"Map",details:"Details",services:"Services",address:"Address",phone:"Phone",book:"Book appointment online",apiTitle:"Connect your AI key"}, es:{about:"Acerca de",privacy:"Privacidad",terms:"T\xE9rminos",by:"Dise\xF1ado por",footBy:"Dise\xF1ado por",showMore:"Ver m\xE1s resultados",searching:"Buscando...",moreOptions:"Aqu\xED hay m\xE1s opciones:",whatsapp:"WhatsApp",call:"Llamar",map:"Mapa",details:"Detalles",services:"Servicios",address:"Direcci\xF3n",phone:"Tel\xE9fono",book:"Reservar cita online",apiTitle:"Conecta tu clave de IA"} }; let charIdx=0; function typeQ(){ const q=TYPED_Q[lang], el=document.getElementById('typed'); if(charIdx{const c=document.querySelector('.cursor');if(c)c.style.animation='none';},2600);} } setTimeout(typeQ,820); function setLang(l){ lang=l; document.documentElement.lang=l; // Toggle welcome screen buttons const lenBtn=document.getElementById('len'); const lesBtn=document.getElementById('les'); if(lenBtn)lenBtn.classList.toggle('on',l==='en'); if(lesBtn)lesBtn.classList.toggle('on',l==='es'); // Chip labels document.querySelectorAll('.chip-label[data-en]').forEach(el=>el.textContent=el.dataset[l]||el.dataset.en); // Input placeholder document.getElementById('inp').placeholder=PLACEHOLDERS[l]; // Footer buttons const ba=document.getElementById('btn-about'); const bp=document.getElementById('btn-privacy'); const bt=document.getElementById('btn-terms'); if(ba)ba.textContent=L[l].about; if(bp)bp.textContent=L[l].privacy; if(bt)bt.textContent=L[l].terms; // Footer brand text const ib=document.getElementById('ifoot-brand'); const fb=document.getElementById('foot-by'); if(ib)ib.textContent='nogales.health \xB7 AI-assisted \xB7 '+L[l].by; if(fb)fb.textContent=L[l].footBy; // Header nav links const navLinks={ 'nav-doctors': {en:'Find a Doctor', es:'Encontrar M\xE9dico'}, 'nav-specs': {en:'Specialties', es:'Especialidades'}, 'nav-how': {en:'How It Works', es:'C\xF3mo Funciona'}, 'nav-fordocs': {en:'For Doctors', es:'Para M\xE9dicos'} }; Object.entries(navLinks).forEach(([id,txt])=>{ const el=document.getElementById(id); if(el)el.textContent=txt[l]||txt.en; }); // Retype welcome question if(!started){document.getElementById('typed').textContent='';charIdx=0;setTimeout(typeQ,200);} } /* ===== INPUT ===== */ const inp=document.getElementById('inp'), sbtn=document.getElementById('sbtn'); inp.addEventListener('input',()=>{inp.style.height='auto';inp.style.height=Math.min(inp.scrollHeight,140)+'px';sbtn.disabled=inp.value.trim()==='';}); inp.addEventListener('keydown',e=>{if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();if(!sbtn.disabled)doSend();}}); /* ===== API KEY ===== */ function checkKey(){return true;} // API key provided server-side via Netlify env var // API key managed server-side /* ===== CHIP / SEND ===== */ document.getElementById('chip-dentist').addEventListener('click',()=>{ const t=lang==='es'?'Necesito un dentista en Nogales':'I need a dentist in Nogales'; inp.value=t;sbtn.disabled=false;doSend(); }); document.getElementById('chip-doctor').addEventListener('click',()=>{ const t=lang==='es'?'Estoy buscando un m\xE9dico':'I\'m looking for a doctor'; inp.value=t;sbtn.disabled=false;doSend(); }); document.getElementById('chip-list').addEventListener('click',()=>{ window.location.href='mailto:nogales.health@gmail.com?subject=List%20My%20Practice%20on%20nogales.health&body=Hello%2C%20I%27d%20like%20to%20list%20my%20practice.%0A%0AName%3A%0ASpecialty%3A%0APhone%3A%0AAddress%3A'; }); function doSend(){ const text=inp.value.trim();if(!text)return; inp.value='';inp.style.height='auto';sbtn.disabled=true; if(!started)startChat(); sendMsg(text); } function startChat(){ started=true; document.getElementById('welcome').classList.add('gone'); document.getElementById('chat').classList.add('on'); document.getElementById('hdr').classList.add('show'); document.getElementById('foot').classList.add('show'); } function resetToWelcome(){ started=false; history=[];lastResults=[];lastSpecialty=''; document.getElementById('welcome').classList.remove('gone'); document.getElementById('chat').classList.remove('on'); document.getElementById('hdr').classList.remove('show'); document.getElementById('foot').classList.remove('show'); document.getElementById('msgs').innerHTML=''; inp.value='';inp.style.height='auto';sbtn.disabled=true; // Retype question document.getElementById('typed').textContent='';charIdx=0;setTimeout(typeQ,300); } /* ===== RENDER HELPERS ===== */ function lsvg(s){const d=s?18:28;return ``;} function vbadge(){return ``;} function addMsg(role,html){ const msgs=document.getElementById('msgs'); const w=document.createElement('div');w.className='msg'+(role==='user'?' u':''); const av=document.createElement('div');av.className='av '+(role==='user'?'me':'ai');av.setAttribute('aria-hidden','true'); if(role!=='user')av.innerHTML=lsvg(true);else av.textContent='\u2192'; const b=document.createElement('div');b.className='bbl '+(role==='user'?'me':'ai');b.innerHTML=html; w.appendChild(av);w.appendChild(b);msgs.appendChild(w);msgs.scrollTop=msgs.scrollHeight; } function showTyping(){ const msgs=document.getElementById('msgs'); const w=document.createElement('div');w.className='msg';w.id='typing'; w.innerHTML=`
${lsvg(true)}
`; msgs.appendChild(w);msgs.scrollTop=msgs.scrollHeight; } function removeTyping(){document.getElementById('typing')?.remove();} /* ===== STARS ===== */ function stars(r){ let h='
'; for(let i=1;i<=5;i++){ if(i<=Math.floor(r))h+='\u2605'; else if(i-0.5<=r)h+='\u2605'; else h+='\u2605'; } return h+`
${r.toFixed(1)}(${r.review_count||Math.round(r*17+10)})`; } /* ===== CARD RENDERER ===== */ function renderCard(r){ const inits=(r.name||'').split(/\s+/).filter(w=>/^[A-Za-z\u00C0-\u024F]/.test(w)).slice(0,2).map(w=>w[0].toUpperCase()).join(''); const waNum=r.whatsapp?r.whatsapp.replace(/\D/g,''):null; const waLink=waNum?`https://wa.me/${waNum}?text=${encodeURIComponent('Hi, I found you on nogales.health and would like to schedule an appointment.')}`:null; const callLink=r.phone?`tel:${r.phone.replace(/\D/g,'')}`:null; const isPrem=r.premium===true; const l=L[lang]; const starsHtml=stars({...r,review_count:r.review_count}); return `
${inits}
${isPrem?vbadge():''}
${r.name}
${r.specialty}
${isPrem?`
Recommended
`:''}
${starsHtml}
${r.address?`
${r.address.split(',')[0]}
`:''} ${r.hours?`
${r.hours}
`:''}
${waLink?`${l.whatsapp}`: callLink?`${l.call}`: ``} ${l.map}
${r.bio?`

${r.bio}

`:''} ${r.review_snippet?`

"${r.review_snippet}"

`:''} ${r.services?.length?`

${l.services}: ${r.services.join(' \xB7 ')}

`:''} ${r.address?`

${l.address}: ${r.address}

`:''} ${r.phone?`

${l.phone}: ${r.phone}

`:''} ${isPrem&&r.booking_link?`

\uD83D\uDCC5 ${l.book} \u2192

`:''}
`; } function toggleDet(id){ const det=document.getElementById('det-'+id); const arr=document.getElementById('darr-'+id); if(!det)return; const open=det.classList.toggle('open'); if(arr)arr.style.transform=open?'rotate(180deg)':''; } /* ===== INJECT PREMIUM ===== */ function injectPremium(results,query){ const q=(query||'').toLowerCase(); const matched=PREMIUM.filter(p=>p.keywords.some(k=>q.includes(k))); if(!matched.length)return results; const withoutPrem=results.filter(r=>!matched.find(p=>p.id===r.id)); return [...matched.slice(0,1),...withoutPrem].slice(0,3); } /* ===== RENDER RESULTS ===== */ function renderResults(data,isMore){ lastResults=data.results||[]; lastSpecialty=data.specialty||''; const final=injectPremium(lastResults,data.query||''); const l=L[lang]; const msgs=document.getElementById('msgs'); const w=document.createElement('div');w.className='msg'; const av=document.createElement('div');av.className='av ai';av.setAttribute('aria-hidden','true');av.innerHTML=lsvg(true); const bbl=document.createElement('div');bbl.className='bbl ai'; if(!isMore&&data.context_message)bbl.innerHTML=`

${data.context_message}

`; else if(isMore)bbl.innerHTML=`

${l.moreOptions}

`; const grid=document.createElement('div');grid.className='results-wrap'; grid.innerHTML=final.map(r=>renderCard(r)).join(''); bbl.appendChild(grid); const smw=document.createElement('div');smw.className='show-more-wrap'; const smb=document.createElement('button');smb.className='show-more'; smb.innerHTML=`${l.showMore}`; smb.onclick=()=>loadMore(smb); smw.appendChild(smb);bbl.appendChild(smw); w.appendChild(av);w.appendChild(bbl);msgs.appendChild(w);msgs.scrollTop=msgs.scrollHeight; } /* ===== LOAD MORE ===== */ async function loadMore(btn){ btn.disabled=true;btn.textContent=L[lang].searching; const exclude=lastResults.map(r=>r.name).join(', '); const prompt=lang==='es'? `Muestra 3 proveedores DIFERENTES para: ${lastSpecialty} en Nogales, Sonora. No repitas: ${exclude}. Mismo formato JSON exacto.`: `Show 3 DIFFERENT providers for: ${lastSpecialty} in Nogales, Sonora. Do NOT repeat: ${exclude}. Same exact JSON format.`; history.push({role:'user',parts:[{text:prompt}]}); try{ const raw=await callGemini(); const parsed=parseResp(raw); if(parsed?.action==='show_results'&&parsed.results?.length){ history.push({role:'model',parts:[{text:raw}]}); renderResults(parsed,true); } }catch(e){} btn.parentElement?.remove(); } /* ===== MARKDOWN ===== */ function md(t){ return t.replace(/&/g,'&').replace(//g,'>') .replace(/\*\*(.+?)\*\*/g,'$1') .replace(/\[([^\]]+)\]\(([^)]+)\)/g,'$1') .replace(/^\- (.+)$/gm,'
  • $1
  • ').replace(/(
  • [\s\S]*?<\/li>)/g,'
      $1
    ') .replace(/\n\n/g,'

    ').replace(/\n/g,'
    ') .replace(/^([^<\n].+)$/gm,m=>m.startsWith('<')?m:`

    ${m}

    `); } /* ===== PARSE RESPONSE ===== */ function parseResp(text){ try{ const m=text.match(/```(?:json)?\s*([\s\S]*?)```/); if(m)return JSON.parse(m[1].trim()); const m2=text.match(/(\{[\s\S]*?"action"\s*:\s*"show_results"[\s\S]*?\})/); if(m2)return JSON.parse(m2[1]); }catch(e){} return null; } /* ===== CALL GEMINI ===== */ async function callGemini(){ // Try Netlify function (GitHub-connected deploys) try{ const r=await fetch('/.netlify/functions/chat',{ method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({messages:history.slice(-12),lang:lang}) }); if(r.ok){const d=await r.json();return d.text;} }catch(e){} // Direct OpenRouter fallback (works on any deploy) const key=window.OR_KEY||''; if(!key)throw new Error('API not configured'); const resp=await fetch('https://openrouter.ai/api/v1/chat/completions',{ method:'POST', headers:{ 'Content-Type':'application/json', 'Authorization':'Bearer '+key, 'HTTP-Referer':'https://nogales.health', 'X-Title':'nogales.health' }, body:JSON.stringify({ model:'nex-agi/nex-n2-pro:free', messages:[{role:'system',content:lang==='es'?SYS_ES:SYS_EN},...history.slice(-12)], temperature:0.35, max_tokens:1400 }) }); if(!resp.ok){const e=await resp.json().catch(()=>({}));throw new Error(e.error?.message||'HTTP '+resp.status);} const d=await resp.json(); return d.choices?.[0]?.message?.content||''; } /* ===== SEND MESSAGE ===== */ async function sendMsg(userText){ addMsg('user',md(userText)); history.push({role:'user',parts:[{text:userText}]}); showTyping();sbtn.disabled=true; try{ const raw=await callGemini();removeTyping(); const parsed=parseResp(raw); if(parsed?.action==='show_results'&&parsed.results?.length){ history.push({role:'model',parts:[{text:raw}]}); renderResults(parsed,false); }else{ history.push({role:'model',parts:[{text:raw}]}); addMsg('assistant',md(raw)); } }catch(err){ removeTyping(); { addMsg('assistant',`

    Something went wrong: ${err.message}. Please try again.

    `); } } sbtn.disabled=inp.value.trim()===''; } /* ===== MODALS ===== */ function openM(id){document.getElementById(id).classList.add('open');} function closeM(id){document.getElementById(id).classList.remove('open');} document.querySelectorAll('.modal-bg').forEach(m=>{m.addEventListener('click',e=>{if(e.target===m)m.classList.remove('open');});}); document.addEventListener('keydown',e=>{if(e.key==='Escape')document.querySelectorAll('.modal-bg.open').forEach(m=>m.classList.remove('open'));}); /* ===== INIT ===== */ if(window.matchMedia('(min-width:768px)').matches)setTimeout(()=>inp.focus(),450); // API key is in Netlify environment variables — never exposed to browser