A Tourism Chatbot That Makes Travel Support Easier

Our virtual travel assistant answers travelers from airports, hotels, and taxi ranks at all hours, changes bookings, and passes tricky cases to your team.

Live Within a Week

Connect your booking system and channels, set your rules, and launch your travel chatbot within about a week.

8 in 10 Handled

Booking changes, pickup checks, and refund questions run on their own, so your team handles complex trips.

Traveler Data Stays Local

Traveler records stay within your country, so you keep control and can meet local data rules.

Live Within a Week

Connect your booking system and channels, set your rules, and launch your travel chatbot within about a week.

8 in 10 Handled

Booking changes, pickup checks, and refund questions run on their own, so your team handles complex trips.

Traveler Data Stays Local

Traveler records stay within your country, so you keep control and can meet local data rules.

how it works

A Chatbot for Travel Agency Teams

A Chatbot for Travel Agency Teams

Travelers write when plans go wrong. AutomatiCworX catches the problem early, explains it clearly, and keeps the trip moving.

Travelers write when plans go wrong. AutomatiCworX catches the problem early, explains it clearly, and keeps the trip moving.

Change of Plans? Sorted in the Chat

Change of Plans? Sorted in the Chat

Change requests tend to arrive the night before. The tourism chatbot checks the booking and your fare rules, makes the change or cancellation and sends the confirmation, so no one waits.

Change requests tend to arrive the night before. The tourism chatbot checks the booking and your fare rules, makes the change or cancellation and sends the confirmation, so no one waits.

tourism chatbot
Ask about your booking...➤
Crest Analytics Consulting
Ask about your pickup...➤

Pickups and Itineraries, Answered in Seconds

Pickups and Itineraries, Answered in Seconds

Travelers waiting in a lobby want one answer: where is my ride? This AI chatbot for travel planning checks the pickup, shares driver status and the day's plan.

Travelers waiting in a lobby want one answer: where is my ride? This AI chatbot for travel planning checks the pickup, shares driver status and the day's plan.

Delay or Storm? Refunds Without the Wait

Delay or Storm? Refunds Without the Wait

When a flight is cancelled or a storm closes a route, everyone writes at once. AWX applies your refund and rebooking rules, treats each request fairly and keeps the full record for your team.

When a flight is cancelled or a storm closes a route, everyone writes at once. AWX applies your refund and rebooking rules, treats each request fairly and keeps the full record for your team.

virtual travel assistant
Ask about your refund...➤
chatbot for travel agency

import { useEffect, useRef, useState } from "react"

import { addPropertyControls, ControlType } from "framer"


/**

* RE_UseCase1_ListingEnquiries - Customer-support chat with auto-sliding deck.

* Loops forever: plays the full 5.6s thread, pauses briefly, then restarts.

*

* @framerSupportedLayoutWidth any

* @framerSupportedLayoutHeight any

* @framerIntrinsicWidth 518

* @framerIntrinsicHeight 482

*/

export default function RE_UseCase1_ListingEnquiries(props) {

const {

background = false,

restartOnHover = true,

startInView = true,

autoLoop = true,

loopDelay = 1800,

} = props

const ref = useRef<HTMLDivElement>(null)

const [run, setRun] = useState(!startInView)

const [take, setTake] = useState(0)


useEffect(() => {

if (!startInView) return

const el = ref.current

if (!el || typeof IntersectionObserver === "undefined") {

setRun(true)

return

}

const io = new IntersectionObserver(

(es) => {

if (es.some((e) => e.isIntersecting)) {

setRun(true)

io.disconnect()

}

},

{ threshold: 0.35 }

)

io.observe(el)

return () => io.disconnect()

}, [startInView])


const last = useRef(0)

const DURATION = 5600


useEffect(() => {

if (!autoLoop || !run) return

const t = setTimeout(() => {

last.current = Date.now()

setTake((x) => x + 1)

}, DURATION + loopDelay)

return () => clearTimeout(t)

}, [autoLoop, loopDelay, run, take])


const restart = () => {

if (!restartOnHover) return

const now = Date.now()

if (now - last.current < DURATION + 400) return

last.current = now

setRun(true)

setTake((t) => t + 1)

}


const replay = () => {

last.current = Date.now()

setRun(true)

setTake((t) => t + 1)

}


useEffect(() => {

if (run) last.current = Date.now()

}, [run])


return (

<div

ref={ref}

className={"u1" + (background ? " bg" : "")}

onMouseEnter={restart}

onClick={replay}

style={{ cursor: "pointer", ...props.style }}

>

<style>{CSS}</style>

{run && (

<div className="feed" key={take}>

{/* User asks about prerequisites and enrollment */}

<div id="m1" className="row r a">

<div>

<div className="in">

<div className="name">Student</div>

<div className="bub">

I'm trying to enroll in Advanced Data

Structures for next semester. Do I need to

have taken Discrete Math first? And when

does registration open?

<div className="meta">

10:15<span className="tick">✓✓</span>

</div>

</div>

</div>

</div>

</div>


{/* AI typing */}

<div id="d1" className="row l a">

<div>

<div className="in">

<div className="dots">

<i />

<i />

<i />

</div>

</div>

</div>

</div>


{/* AI answers from course catalog */}

<div id="m2" className="row l a">

<div>

<div className="in">

<div className="name">AI agent</div>

<div className="bub">

I checked the course catalog for you.

<br />

<br />

Yes, <strong>Discrete Math (CS 201)</strong>

is a strict prerequisite. You must have

passed it with a C or better.

<br />

<br />

Registration for next semester opens on

<strong> November 1st at 8:00 AM</strong>.

<div className="meta">10:15</div>

</div>

</div>

</div>

</div>


{/* AI typing again */}

<div id="d2" className="row l a">

<div>

<div className="in">

<div className="dots">

<i />

<i />

<i />

</div>

</div>

</div>

</div>


{/* AI provides visual deck of admin docs */}

<div id="m3" className="row l a">

<div>

<div className="in">

<div className="name">AI agent</div>

<div className="bub">

Here are the relevant pages from the

registrar and course catalog:


<div className="deck">

<div id="cM" className="cd">

<img

src="https://images.unsplash.com/photo-1523050854058-8df90110c9f1?w=400&q=80"

alt="Course Catalog"

/>

<div className="lb">

Course Catalog

<span>CS Dept</span>

</div>

<div className="ok">✓</div>

</div>

<div id="cJ" className="cd">

<img

src="https://images.unsplash.com/photo-1506784983877-45594efa4cbe?w=400&q=80"

alt="Registrar Calendar"

/>

<div className="lb">

Registrar Calendar

<span>Fall 2024</span>

</div>

</div>

<div id="cB" className="cd">

<img

src="https://images.unsplash.com/photo-1498243691581-b145c3f54a5a?w=400&q=80"

alt="Prerequisite Guide"

/>

<div className="lb">

Prerequisite Guide

<span>Page 8</span>

</div>

</div>

<div id="tJ" className="tap" />

<div id="tM" className="tap" />

</div>


<div className="pills">

<div id="pc" className="pill a">

View enrollment info

<div

id="tC"

className="tap a"

style={{ right: -8, top: -6 }}

/>

</div>

<div className="pill">Other</div>

</div>

<div className="meta">10:16</div>

</div>

</div>

</div>

</div>


{/* Confirmation card */}

<div id="bk" className="row l a">

<div>

<div className="in">

<div className="book">

<div className="ic">🎓</div>

<div>

<div className="t1">

Prerequisites verified · Ready to

enroll

</div>

<div className="t2">

Registration opens Nov 1 · CS 201

requirement met

</div>

</div>

</div>

</div>

</div>

</div>

</div>

)}

{!run && <div className="feed" />}

<div className="input">

Ask about enrollment...<span>➤</span>

</div>

</div>

)

}


addPropertyControls(RE_UseCase1_ListingEnquiries, {

background: {

type: ControlType.Boolean,

title: "Gradient bg",

defaultValue: false,

},

restartOnHover: {

type: ControlType.Boolean,

title: "Restart on hover",

defaultValue: true,

},

startInView: {

type: ControlType.Boolean,

title: "Start when visible",

defaultValue: true,

},

autoLoop: {

type: ControlType.Boolean,

title: "Auto loop",

defaultValue: true,

},

loopDelay: {

type: ControlType.Number,

title: "Loop pause (ms)",

defaultValue: 1800,

min: 0,

max: 8000,

step: 200,

},

})


const CSS = `

/* Root: fully transparent */

.u1{position:relative;container-type:inline-size;box-sizing:border-box;width:100%;height:100%;min-height:340px;border-radius:22px;overflow:hidden;font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;color:#1F2430;display:flex;flex-direction:column;padding:clamp(14px,4%,24px) clamp(14px,4.5%,22px);background:transparent}

.u1.bg{background:transparent}

.u1 *{box-sizing:border-box}

.u1 .a{animation-duration:5.6s;animation-iteration-count:1;animation-fill-mode:forwards;animation-timing-function:cubic-bezier(.22,1,.36,1)}

.u1 .feed{flex:1;min-height:0;display:flex;flex-direction:column;justify-content:flex-end;gap:0}

.u1 .row{display:grid;grid-template-rows:0fr;opacity:0}

.u1 .row>div{min-height:0;overflow:hidden}

.u1 .row .in{padding-bottom:14px;display:flex;flex-direction:column;align-items:flex-start}

.u1 .row.r .in{align-items:flex-end}

.u1 .name{font-size:11.5px;color:#8A94A6;margin:0 4px 4px;font-weight:500}

.u1 .bub{max-width:78%;padding:11px 14px;border-radius:14px;font-size:14px;line-height:1.5;box-shadow:0 1px 2px rgba(16,24,40,.06);position:relative;color:#1F2430}

.u1 .r .bub{background:#5B6472;color:#FFFFFF;border-bottom-right-radius:5px}

.u1 .l .bub{background:#FFFFFF;border-bottom-left-radius:5px}

.u1 .meta{display:flex;justify-content:flex-end;gap:4px;font-size:10px;color:#9AA3B2;margin-top:4px}

.u1 .r .meta{color:rgba(255,255,255,.55)}

.u1 .tick{color:rgba(255,255,255,.75);font-weight:700}

.u1 .dots{display:inline-flex;gap:4px;padding:12px 14px;background:#FFFFFF;border-radius:14px;border-bottom-left-radius:5px;box-shadow:0 1px 2px rgba(16,24,40,.06)}

.u1 .dots i{width:6px;height:6px;border-radius:50%;background:#A6AEBD;animation:u1b 1s ease-in-out infinite}

.u1 .dots i:nth-child(2){animation-delay:.15s}.u1 .dots i:nth-child(3){animation-delay:.3s}

@keyframes u1b{0%,100%{opacity:.35;transform:translateY(0)}50%{opacity:1;transform:translateY(-3px)}}

.u1 .who{font-size:11px;font-weight:700;color:#5B6472;margin-bottom:2px}


/* deck - auto sliding carousel */

.u1 .deck{position:relative;height:150px;width:100%;max-width:260px;margin:10px 0 0 0}

.u1 .cd{position:absolute;left:0;top:0;width:172px;height:118px;border-radius:12px;overflow:hidden;box-shadow:0 6px 18px rgba(16,24,40,.18);background:#000;transform-origin:50% 100%}

.u1 .cd img{width:100%;height:100%;object-fit:cover;display:block}

.u1 .cd .lb{position:absolute;left:0;right:0;bottom:0;padding:6px 9px;background:linear-gradient(transparent,rgba(0,0,0,.72));color:#fff;font-size:11.5px;font-weight:700;display:flex;justify-content:space-between}

.u1 .cd .lb span{font-weight:500;opacity:.9}

.u1 .cd .ok{position:absolute;top:8px;right:8px;width:22px;height:22px;border-radius:50%;background:#12A150;color:#fff;font-size:12px;font-weight:800;display:flex;align-items:center;justify-content:center;opacity:0}


/* Auto-slide: 3 cards loop infinitely */

.u1 #cM{animation:u1cM 4.8s ease-in-out infinite;z-index:3}

.u1 #cJ{animation:u1cJ 4.8s ease-in-out infinite;z-index:2}

.u1 #cB{animation:u1cB 4.8s ease-in-out infinite;z-index:1}

@keyframes u1cM{

0%,33.33% {transform:translate(0,0) rotate(0deg);z-index:3}

33.34%,41.66% {transform:translate(18px,9px) rotate(3deg);z-index:2}

41.67%,100% {transform:translate(36px,16px) rotate(6deg);z-index:1}

}

@keyframes u1cJ{

0%,33.33% {transform:translate(18px,9px) rotate(3deg);z-index:2}

33.34%,41.66% {transform:translate(36px,16px) rotate(6deg);z-index:1}

41.67%,100% {transform:translate(0,0) rotate(0deg);z-index:3}

}

@keyframes u1cB{

0%,33.33% {transform:translate(36px,16px) rotate(6deg);z-index:1}

33.34%,41.66% {transform:translate(0,0) rotate(0deg);z-index:3}

41.67%,100% {transform:translate(18px,9px) rotate(3deg);z-index:2}

}


/* ✓ badge visibility */

@keyframes u1okM{0%,33.33%{opacity:1}33.34%,100%{opacity:0}}

@keyframes u1okJ{0%,33.33%{opacity:0}33.34%,66.66%{opacity:1}66.67%,100%{opacity:0}}

@keyframes u1okB{0%,66.66%{opacity:0}66.67%,100%{opacity:1}}

.u1 #cM .ok{animation:u1okM 4.8s steps(1) infinite}

.u1 #cJ .ok{animation:u1okJ 4.8s steps(1) infinite}

.u1 #cB .ok{animation:u1okB 4.8s steps(1) infinite}


/* tap ripples */

.u1 .tap{position:absolute;width:26px;height:26px;border-radius:50%;border:2px solid #fff;background:rgba(255,255,255,.35);opacity:0;pointer-events:none;z-index:9;animation-timing-function:ease-out;animation-iteration-count:infinite}

.u1 #tJ{left:140px;top:62px;animation:u1tJ 4.8s ease-out infinite}

.u1 #tM{left:72px;top:54px;animation:u1tM 4.8s ease-out infinite}

@keyframes u1tJ{0%,33.33%{opacity:0;transform:scale(.4)}35%,38%{opacity:1;transform:scale(.7)}41.66%,100%{opacity:0;transform:scale(1.6)}}

@keyframes u1tM{0%,66.66%{opacity:0;transform:scale(.4)}68.33%,71.33%{opacity:1;transform:scale(.7)}75%,100%{opacity:0;transform:scale(1.6)}}


/* quick replies + booking */

.u1 .pills{display:flex;gap:8px;margin-top:10px}

.u1 .pill{font-size:12.5px;font-weight:600;padding:7px 12px;border-radius:999px;border:1.5px solid #5B6472;color:#5B6472;background:#FFFFFF;position:relative}

/* Primary CTA: outline by default, green fill on click */

.u1 #pc{animation-name:u1pc;animation-timing-function:steps(1)}

@keyframes u1pc{

0%,82.143%{background:transparent;color:#5B6472;border-color:#5B6472}

82.321%,100%{background:#12A150;color:#FFFFFF;border-color:#12A150}

}

.u1 #tC{left:auto;top:auto;animation-name:u1tC;position:absolute}

@keyframes u1tC{0%,80.357%{opacity:0;transform:scale(.4)}82.143%{opacity:1;transform:scale(.7)}88.393%,100%{opacity:0;transform:scale(1.6)}}

.u1 .book{display:flex;gap:10px;align-items:center;background:#FFFFFF;border-radius:14px;padding:11px 14px;box-shadow:0 1px 2px rgba(16,24,40,.06);max-width:88%;color:#1F2430}

.u1 .book .ic{width:36px;height:36px;border-radius:10px;background:rgba(18,161,80,.14);color:#12A150;display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}

.u1 .book .t1{font-size:13px;font-weight:700}.u1 .book .t2{font-size:12px;color:#6B7280;margin-top:2px}


/* Message entry animations */

@keyframes u1m1{0%,0.000%{grid-template-rows:0fr;opacity:0;transform:translateY(8px)}5.357%,100%{grid-template-rows:1fr;opacity:1;transform:none}}

@keyframes u1m2{0%,8.929%{grid-template-rows:0fr;opacity:0;transform:translateY(8px)}14.286%,100%{grid-template-rows:1fr;opacity:1;transform:none}}

@keyframes u1m3{0%,50.000%{grid-template-rows:0fr;opacity:0;transform:translateY(8px)}55.357%,100%{grid-template-rows:1fr;opacity:1;transform:none}}

@keyframes u1m4{0%,62.500%{grid-template-rows:0fr;opacity:0;transform:translateY(8px)}67.857%,100%{grid-template-rows:1fr;opacity:1;transform:none}}

@keyframes u1bk{0%,89.286%{grid-template-rows:0fr;opacity:0;transform:translateY(8px)}94.643%,100%{grid-template-rows:1fr;opacity:1;transform:none}}

.u1 #m1{animation-name:u1m1}.u1 #m2{animation-name:u1m2}.u1 #m3{animation-name:u1m3}.u1 #m4{animation-name:u1m4}.u1 #bk{animation-name:u1bk}


/* typing rows collapse once the reply lands */

@keyframes u1d1x{0%,3.571%{grid-template-rows:0fr;opacity:0}6.250%,8.036%{grid-template-rows:1fr;opacity:1}10.714%,100%{grid-template-rows:0fr;opacity:0}}

@keyframes u1d2x{0%,55.357%{grid-template-rows:0fr;opacity:0}58.036%,61.607%{grid-template-rows:1fr;opacity:1}64.286%,100%{grid-template-rows:0fr;opacity:0}}

.u1 #d1{animation-name:u1d1x}.u1 #d2{animation-name:u1d2x}


/* Input bar */

.u1 .input{margin-top:8px;height:44px;border-radius:12px;background:#FFFFFF;border:1px solid #E3E6EC;display:flex;align-items:center;padding:0 14px;font-size:13.5px;color:#9AA3B2;flex-shrink:0}

.u1 .input span{margin-left:auto;opacity:.7;color:#5B6472}


/* narrow (phone) */

@container (max-width: 400px) {

.u1 .bub{max-width:92%;font-size:13.5px;padding:10px 12px}

.u1 .pills{flex-wrap:wrap}

.u1 .pill{white-space:nowrap;font-size:12px;padding:6px 11px}

.u1 .call,.u1 .book{max-width:100%}

.u1 .deck{max-width:100%}

.u1 .input{height:42px;font-size:13px}

}

`

Ask about your documents...➤

Pre-Trip Paperwork, Done Before Departure

Pre-Trip Paperwork, Done Before Departure

Missing passport scans and unpaid deposits cause last-minute panic. AWX chases the documents, confirms deposits and answers common pre-trip questions, so every trip leaves complete.

Missing passport scans and unpaid deposits cause last-minute panic. AWX chases the documents, confirms deposits and answers common pre-trip questions, so every trip leaves complete.

Frequently Asked
Questions

Frequently Asked Questions

Straight answers for tour operators and travel agencies on bookings, pickups, refunds, languages and how the virtual travel assistant works.

Straight answers for tour operators and travel agencies on bookings, pickups, refunds, languages and how the virtual travel assistant works.

What is a tourism chatbot?

A tourism chatbot helps travelers get quick answers without waiting for a member of staff. It can check booking details, help with changes or refunds, and pass more complicated requests to your team when a person needs to step in.

Can a tourism chatbot help travel agency teams?

What does a virtual travel assistant do?

Can it help with travel planning as well?

How long does it take to get started?

Ready to Talk?

Book a short demo and see AutomatiCworX handle your travelers' questions at any hour.