'); paymentWindow.document.close(); } } catch (e) { console.warn('Failed to open payment window:', e); }bbShowLoading('Reserving slots with ranger...');const tourTypeMap = { 'private-town': 'private_town_tour', 'living-lake': 'living_at_the_lake', 'twilight': 'twilight_tour', 'large-group': 'large_group_tour', 'mines': 'mines_mills_tour' };const payload = { date: bbState.selectedDate, time: bbState.selectedTime, party_size: partySize, tour_type: tourTypeMap[tourKey] || 'large_group_tour', vehicle_acknowledgment: tourKey === 'mines' ? (document.getElementById('mines-vehicle-ack') ? document.getElementById('mines-vehicle-ack').checked : false) : false, guest: { name: name, email: email, phone: phone } };try { let csrfToken = ''; let recaptchaSiteKey = '';try { const csrfResponse = await fetchWithTimeout(BOOKING_API, { method: 'GET', credentials: 'include', timeout: 10000 });if (csrfResponse.ok) { const csrfData = await csrfResponse.json(); csrfToken = csrfData.csrf_token; recaptchaSiteKey = csrfData.recaptcha_site_key; } } catch (csrfErr) { console.warn('Could not retrieve CSRF token or site key:', csrfErr); }let recaptchaToken = '';if (recaptchaSiteKey) { try { await Promise.race([ loadRecaptchaScript(recaptchaSiteKey), new Promise(function(_, reject) { setTimeout(function() { reject(new Error('reCAPTCHA script load timeout')); }, 5000); }) ]);if (typeof grecaptcha !== 'undefined') { recaptchaToken = await Promise.race([ grecaptcha.execute(recaptchaSiteKey, { action: 'submit_booking' }), new Promise(function(_, reject) { setTimeout(function() { reject(new Error('reCAPTCHA execution timeout')); }, 4000); }) ]); } } catch (err) { console.warn('reCAPTCHA execution failed, proceeding without token:', err); } }payload.recaptcha_token = recaptchaToken;const response = await fetchWithTimeout(BOOKING_API, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken }, credentials: 'include', body: JSON.stringify(payload), timeout: 10000 });let result = {};try { result = await response.json(); } catch (jsonErr) { console.warn('Could not parse response JSON:', jsonErr); }if (response.ok && result.status === 'success') { const totalPrice = tour ? tour.calcPrice(partySize) : partySize * 25.00;document.getElementById('bb-amount-display').textContent = '$' + totalPrice.toFixed(2) + ' DUE'; document.getElementById('bb-confirm-id').textContent = result.booking_id || '--'; document.getElementById('bb-confirm-party').textContent = partySize + ' Guest(s)';const displayDate = new Date(bbState.selectedDate + 'T12:00:00').toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });document.getElementById('bb-confirm-datetime').textContent = tourName + ' on ' + displayDate + ' @ ' + bbState.selectedTime;const invoiceLink = document.getElementById('bb-invoice-link'); const countdownEl = document.getElementById('bb-redirect-countdown');if (invoiceLink && result.payment_link && isTrustedRedirectUrl(result.payment_link)) { invoiceLink.href = result.payment_link; invoiceLink.style.display = 'inline-flex'; } else if (invoiceLink) { invoiceLink.style.display = 'none'; }const cancelLink = document.getElementById('bb-cancel-link');if (cancelLink && result.booking_id && result.token) { cancelLink.href = 'https://us-west2-bodie-tours-prod.cloudfunctions.net/cancel-tour?booking_id=' + encodeURIComponent(result.booking_id) + '&token=' + encodeURIComponent(result.token); }let openedInNewTab = false;if (paymentWindow) { try { if (!paymentWindow.closed) { if (result.payment_link && isTrustedRedirectUrl(result.payment_link)) { paymentWindow.location.href = result.payment_link; openedInNewTab = true; } else { paymentWindow.close(); } } } catch (e) { console.warn('Failed to set payment window location:', e); } }if (countdownEl) { if (openedInNewTab) { countdownEl.innerHTML = 'Your invoice has been opened in a new tab. If it did not open, click Pay Your Invoice Now above.'; } else { countdownEl.innerHTML = 'Please click the Pay Your Invoice Now button above to complete your secure payment.'; } }bbGoTo(4); } else { if (paymentWindow) { try { paymentWindow.close(); } catch (e) {} }if (response.status === 400) { errMsg.textContent = result.message || 'Validation error. Please check your inputs.'; } else if (response.status === 409) { errMsg.textContent = result.message || 'The requested slot is already booked. Please choose another slot.'; } else if (response.status === 429) { errMsg.textContent = 'Too many booking attempts. Please wait a moment and try again.'; } else if (response.status === 500) { errMsg.textContent = 'A temporary server error occurred. Please try again shortly.'; } else { errMsg.textContent = result.message || 'The slot is no longer available. Please select another time.'; }errBox.style.display = 'flex'; } } catch (err) { if (paymentWindow) { try { paymentWindow.close(); } catch (e) {} }console.error('Booking failed:', err); errMsg.textContent = 'Network or connection error. Please try again.'; errBox.style.display = 'flex'; } finally { bbState.isSubmitting = false;if (confirmBtn) { confirmBtn.disabled = false; }bbHideLoading(); } }function bbAnnounce(message) { const announcer = document.getElementById('bb-announcer');if (announcer) { announcer.textContent = '';setTimeout(function() { announcer.textContent = message; }, 50); } }function bbGoTo(step) { if (step < 4) { bbClearTimers(); }document.querySelectorAll('.bb-step').forEach(function(pane) { pane.classList.remove('active'); });document.getElementById('step-pane-' + step).classList.add('active');document.getElementById('bb-progress-bar').style.width = (step / 4) * 100 + '%';const progressContainer = document.getElementById('bb-progress-container');if (progressContainer) { progressContainer.setAttribute('aria-valuenow', step + 1); }document.querySelectorAll('.bb-progress-step').forEach(function(dot, index) { if (index < step) { dot.className = 'bb-progress-step completed'; dot.removeAttribute('aria-current'); } else if (index === step) { dot.className = 'bb-progress-step active'; dot.setAttribute('aria-current', 'step'); } else { dot.className = 'bb-progress-step'; dot.removeAttribute('aria-current'); } });if (step === 1) { bbFetchMonthAvailability(bbState.currentYear, bbState.currentMonth).then(function() { bbRenderCalendar(); }); }if (step === 2) { bbPopulateSlots(); }if (step === 3) { bbUpdateStep3Fields(); }const heading = document.getElementById('bb-step-heading-' + step);if (heading) { heading.focus({ preventScroll: true }); bbAnnounce('Step ' + (step + 1) + ' of 5: ' + heading.textContent.trim()); }const widget = document.getElementById('bodie-booking-widget');if (widget) { window.scrollTo({ top: widget.offsetTop - 30, behavior: 'smooth' }); } }function bbSelectTour(tourKey) { bbState.selectedTour = tourKey;document.querySelectorAll('.bb-tour-card').forEach(function(card) { const isSelected = card.getAttribute('data-tour') === tourKey;if (isSelected) { card.classList.add('selected'); card.setAttribute('aria-checked', 'true'); card.setAttribute('aria-pressed', 'true'); card.setAttribute('tabindex', '0'); } else { card.classList.remove('selected'); card.setAttribute('aria-checked', 'false'); card.setAttribute('aria-pressed', 'false'); card.setAttribute('tabindex', '-1'); } });const tourName = TOURS[tourKey] ? TOURS[tourKey].name : 'Tour';bbAnnounce('Selected tour: ' + tourName);document.getElementById('bb-to-step-1').disabled = false;bbState.selectedDate = null; bbState.selectedTime = null;document.getElementById('bb-to-step-2').disabled = true; document.getElementById('bb-to-step-3').disabled = true; }function bbUpdateStep3Fields() { const tourKey = bbState.selectedTour; const tour = TOURS[tourKey];const ackGroup = document.getElementById('mines-vehicle-ack-group'); const ackInput = document.getElementById('mines-vehicle-ack'); const partyInput = document.getElementById('guest-party'); const partyLabel = document.querySelector('label[for="guest-party"]');if (tourKey === 'mines') { ackGroup.style.display = 'block'; ackInput.required = true; } else { ackGroup.style.display = 'none'; ackInput.required = false; ackInput.checked = false; }const maxParty = tour ? tour.maxParty : 20;partyInput.max = maxParty; partyInput.placeholder = 'e.g., 4 (maximum ' + maxParty + ')'; partyLabel.textContent = 'Number of Guests (Required, max ' + maxParty + ')'; }async function bbRetryCalendarFetch() { await bbFetchMonthAvailability(bbState.currentYear, bbState.currentMonth); bbRenderCalendar(); }function bbStartOver() { bbClearTimers();bbState = { selectedTour: null, currentYear: new Date().getFullYear(), currentMonth: new Date().getMonth(), selectedDate: null, selectedTime: null, availableDates: {}, redirectTimeout: null, redirectInterval: null, calendarFetchFailed: false, isSubmitting: false };const form = document.getElementById('bb-booking-form');if (form) { form.reset(); }const errBox = document.getElementById('bb-error-box');if (errBox) { errBox.style.display = 'none'; }document.getElementById('bb-to-step-1').disabled = true; document.getElementById('bb-to-step-2').disabled = true; document.getElementById('bb-to-step-3').disabled = true;document.querySelectorAll('.bb-tour-card').forEach(function(card) { card.classList.remove('selected'); card.setAttribute('aria-checked', 'false'); card.setAttribute('aria-pressed', 'false'); });bbGoTo(0); }function bbShowLoading(text) { const loading = document.getElementById('bb-loading'); const loadingText = document.getElementById('bb-loading-text');if (loadingText) { loadingText.textContent = text; }if (loading) { loading.setAttribute('aria-hidden', 'false'); loading.classList.add('active'); } }function bbHideLoading() { const loading = document.getElementById('bb-loading');if (loading) { loading.setAttribute('aria-hidden', 'true'); loading.classList.remove('active'); } }window.bbSelectTour = bbSelectTour; window.bbRetryCalendarFetch = bbRetryCalendarFetch; window.bbStartOver = bbStartOver; window.bbChangeMonth = bbChangeMonth; window.bbGoTo = bbGoTo; window.bbSubmitBooking = bbSubmitBooking; window.bbInit = bbInit;function bbSafeInit() { if (!document.getElementById('bodie-booking-widget')) { return; }bbInit(); }if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', bbSafeInit); } else { bbSafeInit(); } })();

Bodie Ghost Walks 2026

Four Extraordinary Nights in Bodie, three tours each night to choose from!

Tickets go on sale March 15 for members.

NOT A MEMBER? Tickets for non-members go on sale March 31st!
Please click on the dates below to be redirected to the event registration page for the date you’d like to attend:

Details:
The park will be open to the public afterhours until 10pm during each Ghost Walk evening. Please be respectful of park staff during this event and exit the park promptly at 10pm. Thank you to Bodie State Historic Park staff for helping us put on this special evening!

Presale tickets available to Bodie Foundation Members on March 15th at 9 am.
Ticket sales open to the general public March 31 at 9 am.

To become a member, please sign up here.

For more info please call (760) 932-7574.
Entrance fee apply to all visitors ($8 Adults – $5 under 18).

*Tickets are refundable up until 30 days before your scheduled tour. Any refund requests will not be accepted after this time. No exceptions

Join our mailing list

Love Bodie State Historic Park? Stay connected for information on Bodie and the Foundation’s work.