Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# CHANGELOG

## 2026-11-10 - One commercial spot per page; Juárez dentist crossing guide (draft)

- Rule: a page shows a sponsor card or a network ad, never both. On the five El Paso/Juárez crossing pages and on sponsored guides, the sponsor replaces the Adsterra unit.
- New guide (EN and ES): going to a dentist in Ciudad Juárez from El Paso or New Mexico. Covers which bridge to check, documents, how to look up a dentist's cédula, and timing the return. Agency rules link to CBP, SEP and CONAMED. No prices or treatment advice. The sponsor card sits in the guide under the vetting checklist via `<FeaturedSponsor />`.
- Medication guides place the sponsor with `<FeaturedSponsor />` after the current-wait links.
- Sponsor links have distinct accessible names (for example "WhatsApp: <business>").
- Checks: full `npm test` passes after a prerendered build; entry bundle 61.92 KB gzip. Headless Chrome 390px: sponsored pages show 1 card and 0 ads; San Ysidro and the SENTRI guide show 0 cards and 1 ad.

## 2026-11-10 - Sponsored listings, first sponsor (draft)

- New `SponsoredCard` and `src/lib/sponsors.js`: one labeled sponsor per placement, set by port number or guide slug, with optional `since`/`until` dates. Each card is marked Sponsored/Patrocinado and says Border Pulse has not evaluated the business's care.
- First sponsor: Constandse Esthetic & Dent (Ciudad Juárez dentist), on the five El Paso/Juárez crossing pages (above the ad) and on both medication guides (under the current-wait links). Links carry UTM tags; clicks log `sponsor-click` with sponsor, placement and action (site or WhatsApp), no free text.
- Privacy notice (EN/ES) now says clicks on sponsored listings are counted with Umami and that sponsored listings are labeled placements from local businesses.
- Checks: full `npm test` passes after a prerendered build; entry bundle 62.02 KB gzip (budget 62.25). Headless Chrome 390px: card on PDN and both guides, none on San Ysidro, click logs the event, no overflow.
- Open: the site link points at the clinic's preview deployment until its own domain is live.
## 2026-11-10 - Crossing titles and descriptions match how people search (draft)

- Crossing page titles now follow the query shape from Search Console: "<crossing> border wait times today" (EN) and "Tiempos de espera en <crossing> hoy" (ES). Bridges and ports of entry use the name people type: "Anzalduas International Bridge (Hidalgo/Pharr)", "Santa Teresa Port of Entry", "Andrade (Los Algodones)", "Eagle Pass International Bridge II" and others.
Expand Down
4 changes: 4 additions & 0 deletions DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -577,3 +577,7 @@ Adsterra reported 21 impressions and $0.03 for Nov 5 to 9 from the single home-p
## 2026-11-10 - Light-mode slate-500 is one notch darker for AA contrast

Stock `slate-500` (#62748e) measured 4.47:1 on the light page background, just under 4.5:1, on every page. Light mode overrides `--color-slate-500` to #5e7088 (4.75:1) instead of editing hundreds of class names; `.dark` restores the stock value so dark mode does not lose contrast.

## 2026-11-10 - One commercial spot per page

A page carries a sponsor card or a network ad, never both, and always below the answer. A sponsor replaces the Adsterra unit on its pages. Sponsors are configured in `src/lib/sponsors.js`, one per port or guide, always labeled Sponsored/Patrocinado with the "has not evaluated" line. Sponsor copy states facts only (name, city, links); no medical or price claims in Border Pulse's voice.
7 changes: 7 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,3 +339,10 @@ Snapshot of features live on borderpulse.com today.
- Bounded dashboard ad-slot diagnostics through existing Umami: script/DOM/
container visibility stages only, not billed impressions or revenue. Actual
ad-network totals still require publisher reports.

## Backlog: sponsored placements (added 2026-11-10)

- Pharmacy sponsor for the medication guides (highest-traffic slot). Not being pitched yet; needs a trusted contact and a vetting pass first.
- City guides as sponsor inventory: Tijuana, Los Algodones, Nuevo Progreso, Nogales. One featured business per category section.
- Self-serve "feature your business" page, after 2 to 3 paying sponsors and a real click number to show.
- Swap the first sponsor's link from the preview deployment to its own address once that site launches.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions src/components/blog/FeaturedSponsor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useContext } from 'react';
import { useParams } from 'react-router-dom';
import { LangContext } from '@/lib/LangContext';
import SponsoredCard from '@/components/sponsors/SponsoredCard';
import { sponsorForGuide } from '@/lib/sponsors';

// Places this guide's sponsor (if any) where the article calls for it.
export default function FeaturedSponsor() {
const lang = useContext(LangContext) || 'en';
const { slug } = useParams();
return <SponsoredCard sponsor={sponsorForGuide(slug)} placement={`guide-${slug}`} language={lang} />;
}
5 changes: 5 additions & 0 deletions src/components/blog/InArticleAd.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { useContext } from 'react';
import { useParams } from 'react-router-dom';
import AdsterraBanner from '@/components/ads/AdsterraBanner';
import { LangContext } from '@/lib/LangContext';
import { sponsorForGuide } from '@/lib/sponsors';

// Mid-article ad for long guides. A post that uses it sets `inArticleAd: true`
// in frontmatter so BlogPost skips its end-of-post slot: one container per page.
// One commercial spot per page: a guide with a sponsor shows no network ad.
export default function InArticleAd() {
const lang = useContext(LangContext) || 'en';
const { slug } = useParams();
if (sponsorForGuide(slug)) return null;
return (
<div className="not-prose">
<AdsterraBanner label={lang === 'es' ? 'Publicidad' : 'Advertisement'} language={lang} />
Expand Down
2 changes: 2 additions & 0 deletions src/components/blog/MdxComponents.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import BestTimeChart from './BestTimeChart';
import CrossingRankings from './CrossingRankings';
import InArticleAd from './InArticleAd';
import CrossingWaitLinks from './CrossingWaitLinks';
import FeaturedSponsor from './FeaturedSponsor';

function CrossingLink({ slug, children }) {
return (
Expand All @@ -20,6 +21,7 @@ export const mdxComponents = {
CrossingLink,
InArticleAd,
CrossingWaitLinks,
FeaturedSponsor,
a: (props) => {
const isExternal = /^https?:\/\//.test(props.href || '');
if (isExternal) {
Expand Down
51 changes: 51 additions & 0 deletions src/components/sponsors/SponsoredCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ExternalLink, MessageCircle } from 'lucide-react';
import { sponsorUrl } from '@/lib/sponsors';
import { track } from '@/lib/analytics';

// A labeled paid placement. Clicks log `sponsor-click` (sponsor id, placement,
// action) so each sponsor gets a monthly count. No free text is sent.
export default function SponsoredCard({ sponsor, placement, language = 'en' }) {
if (!sponsor) return null;
const es = language === 'es';
const log = action => track('sponsor-click', { sponsor: sponsor.id, placement, action });
return (
<aside
className="not-prose my-6 rounded-xl border border-slate-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900"
aria-label={es ? 'Anuncio patrocinado' : 'Sponsored listing'}
data-sponsor={sponsor.id}
>
<p className="text-[10px] font-semibold uppercase tracking-wider text-slate-600 dark:text-slate-400">
{es ? 'Patrocinado' : 'Sponsored'} · {sponsor.category[es ? 'es' : 'en']} · {sponsor.city}
</p>
<p className="mt-1 text-base font-semibold text-slate-900 dark:text-white">{sponsor.name}</p>
<p className="mt-1 text-sm text-slate-600 dark:text-slate-300">{sponsor.blurb[es ? 'es' : 'en']}</p>
<div className="mt-3 flex flex-wrap gap-2">
<a
href={sponsorUrl(sponsor, placement)}
target="_blank"
rel="sponsored noopener"
onClick={() => log('site')}
aria-label={`${es ? 'Ver sitio' : 'Visit site'}: ${sponsor.name}`}
className="inline-flex min-h-11 items-center gap-1.5 rounded-md border border-slate-300 px-3 py-2 text-sm font-medium text-slate-800 hover:bg-slate-50 dark:border-gray-700 dark:text-slate-100 dark:hover:bg-gray-800"
>
{es ? 'Ver sitio' : 'Visit site'}<ExternalLink aria-hidden="true" className="h-3.5 w-3.5" />
</a>
{sponsor.whatsapp && (
<a
href={`https://wa.me/${sponsor.whatsapp}`}
target="_blank"
rel="sponsored noopener"
onClick={() => log('whatsapp')}
aria-label={`WhatsApp: ${sponsor.name}`}
className="inline-flex min-h-11 items-center gap-1.5 rounded-md border border-emerald-700 px-3 py-2 text-sm font-medium text-emerald-800 hover:bg-emerald-50 dark:text-emerald-300 dark:hover:bg-emerald-950/40"
>
<MessageCircle aria-hidden="true" className="h-3.5 w-3.5" />WhatsApp
</a>
)}
</div>
<p className="mt-3 text-xs text-slate-600 dark:text-slate-400">
{es ? 'Espacio patrocinado. Border Pulse no ha evaluado la atención de este negocio.' : 'Sponsored placement. Border Pulse has not evaluated this business’s care.'}
</p>
</aside>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ When in doubt, fill the U.S. prescription on the U.S. side and use the Mexican t

<CrossingWaitLinks items={[["san-ysidro", "San Ysidro (Tijuana)"], ["andrade", "Andrade (Los Algodones)"], ["nogales-deconcini", "Nogales (DeConcini)"], ["el-paso-paso-del-norte-pdn", "El Paso (Paso del Norte)"], ["progreso-progreso-international-bridge", "Progreso (Nuevo Progreso)"]]} />

<FeaturedSponsor />

## The core rule

For most prescription medications, CBP applies a personal-use standard: a small quantity (commonly described as up to a 90-day supply per medication) of an FDA-approved drug, with a valid prescription from a licensed practitioner, may be brought back into the U.S. for the importer's personal use. The drug must be declared at the port of entry on request.
Expand Down
95 changes: 95 additions & 0 deletions src/content/blog/dentist-in-juarez-from-el-paso-new-mexico.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
title: "Going to a dentist in Ciudad Juárez from El Paso or New Mexico: a crossing guide"
description: "Which bridge to use, what to bring, how to check a dentist's license in Mexico, and how to time the trip back. For patients from El Paso, Las Cruces and southern New Mexico."
slug: dentist-in-juarez-from-el-paso-new-mexico
date: "2026-11-10"
author: sebastian
pillar: crossing-guides
lang: en
tags:
- juarez
- el-paso
- new-mexico
- dental
- medical-tourism
- paso-del-norte
translationKey: juarez-dentist-crossing-guide
hero: /og/blog/dentist-in-juarez-from-el-paso-new-mexico.png
relatedCrossings:
- "240202"
- "240201"
- "240104"
- "240801"
officialSources:
- label: "CBP Border Wait Times (live CBP data)"
url: "https://bwt.cbp.gov/"
- label: "CBP: Western Hemisphere Travel Initiative documents"
url: "https://www.cbp.gov/travel/us-citizens/western-hemisphere-travel-initiative"
- label: "SEP: Registro Nacional de Profesionistas (license lookup)"
url: "https://www.cedulaprofesional.sep.gob.mx/"
- label: "CONAMED: medical arbitration commission"
url: "https://www.gob.mx/conamed"
---

People from El Paso, Las Cruces and southern New Mexico cross into Ciudad Juárez for dental work as a day trip. The dentistry is the clinic's job. This guide covers the part around it: which bridge to use, what to bring, how to check a dentist before you book, and how to time the trip back.

## The short version

- **Pick the bridge by where you start and how you travel.** Walking from downtown El Paso: Paso del Norte. Driving: Bridge of the Americas or Ysleta-Zaragoza. Coming from New Mexico: look at Santa Teresa.
- **Bring a document CBP accepts for re-entry by land.** CBP lists them under the [Western Hemisphere Travel Initiative](https://www.cbp.gov/travel/us-citizens/western-hemisphere-travel-initiative).
- **Check the dentist's license before you book.** Mexico's education ministry runs a public [license lookup](https://www.cedulaprofesional.sep.gob.mx/).
- **Plan the return, not just the appointment.** The wait to come back is the part that varies.

<CrossingWaitLinks items={[["el-paso-paso-del-norte-pdn", "Paso del Norte (PDN)"], ["el-paso-bridge-of-the-americas-bota", "Bridge of the Americas"], ["el-paso-ysleta", "Ysleta-Zaragoza"], ["santa-teresa-santa-teresa-port-of-entry", "Santa Teresa"]]} />

## Which bridge to use

| Starting from | Crossing to check first | Why |
|---|---|---|
| Downtown El Paso, on foot | [Paso del Norte](/crossing/el-paso-paso-del-norte-pdn/) | It connects downtown El Paso to downtown Juárez, and CBP reports a pedestrian lane there. |
| Central El Paso, driving | [Bridge of the Americas](/crossing/el-paso-bridge-of-the-americas-bota/) | Known locally as Puente Libre. It handles passenger vehicles, including larger ones. |
| East El Paso, driving | [Ysleta-Zaragoza](/crossing/el-paso-ysleta/) | It is the eastern bridge, so it can save a drive across town. |
| Las Cruces or southern New Mexico | [Santa Teresa](/crossing/santa-teresa-santa-teresa-port-of-entry/) | It sits west of El Paso in New Mexico. Compare it with the El Paso bridges before you leave. |

Ask the clinic which bridge is closest to them and whether they offer a pickup. Some Juárez clinics do, and it changes which bridge makes sense.

If you are choosing between the two central bridges, the hour-by-hour comparison is in [Paso del Norte vs Bridge of the Americas](/blog/paso-del-norte-vs-bridge-of-the-americas/).

## What to bring

- **Your travel document.** U.S. citizens returning by land need a document CBP accepts, such as a U.S. passport book or passport card. The full list is on [CBP's page](https://www.cbp.gov/travel/us-citizens/western-hemisphere-travel-initiative).
- **Your dental records.** Recent X-rays and a list of the medications you take help the dentist plan before you sit down.
- **A way to pay that the clinic confirmed.** Ask ahead whether they take cards, dollars or pesos.
- **The clinic's address and phone number on paper.** Phone service can drop near the bridges.

## How to check a dentist before you book

Border Pulse does not rate clinics. These are checks you can do yourself.

1. **Look up the license.** Every dentist practicing in Mexico has a professional license number (cédula profesional). Ask for it and search it in the [public registry](https://www.cedulaprofesional.sep.gob.mx/). A specialist, such as an implant or oral rehabilitation dentist, has a separate specialty license. Ask for that one too.
2. **Ask for a written treatment plan and an itemized quote.** It should say what is included: X-rays, the implant, the abutment, the crown, follow-up visits.
3. **Ask what happens if something goes wrong after you are home.** Who do you call, is there a warranty, and does a fix mean another trip?
4. **Ask how many visits the work takes.** Implants and full restorations usually take more than one trip, so the crossing becomes part of the cost.
5. **Know where complaints go.** Mexico's medical arbitration commission, [CONAMED](https://www.gob.mx/conamed), handles disputes between patients and health providers.

<FeaturedSponsor />

## Timing the trip back

The appointment has a fixed time. The return wait does not. The chart shows the typical northbound wait at Paso del Norte by day and hour, from the last 30 days of CBP reports.

<BestTimeChart slug="el-paso-paso-del-norte-pdn" title="Paso del Norte: median northbound wait, last 30 days" />

- **Book around the quiet hours** the chart shows, when you have a choice.
- **Check the current wait before you leave the clinic**, not when you reach the line. Each crossing page shows the time CBP last reported.
- **Have a second bridge in mind.** If one is backed up, another may be shorter.

The chart is history, not a forecast. Holidays, weather and lane closures change it.

## Bringing medication back

If the dentist prescribes something, the rules for bringing it into the U.S. are in [Bringing prescription medication back from Mexico](/blog/bringing-prescription-medication-back-from-mexico/). Declare what you carry.

## How this guide was made

Wait patterns come from the official [CBP Border Wait Times](https://bwt.cbp.gov/) feed, stored by Border Pulse and summarized as medians. Document and licensing points link to the agency that sets them. This guide does not give medical advice or recommend a treatment.
Loading
Loading