- Reach the right customer using
reach_person(handles voicemail and the gatekeeper problem) - Politely decline if the customer doesn’t want to participate, without forcing them through the survey
- Collect an NPS score, resolution status, and open-ended feedback in a single conversational task
- Create an Amazon Connect task linked to the original
ContactIdviaRelatedContactId, so the survey is reportable in Connect’s contact search and historical metrics
How It Works
Prerequisites
- Python 3.10 or later
- A Guava account with an API key and a phone number — sign up at app.goguava.ai
- An AWS account with an Amazon Connect instance
- The ContactId of the original support call you want to survey about (Amazon Connect surfaces this in the Contact Control Panel and contact search)
Step 1: Install Guava
Choose whichever package manager you prefer:boto3 for the Amazon Connect API:
Step 2: Set Up Amazon Connect
If you already have a Connect instance configured, skip to the parts you haven’t done yet.2a. Create or locate your Connect instance
- Open the Amazon Connect console.
- Create an instance if you don’t have one, or select an existing one.
- Note the Instance ID — it’s the UUID at the end of the instance ARN:
2b. Create a contact flow for survey tasks
Amazon Connect tasks need a dedicated contact flow — the default queue flow does not support tasks.- In your Connect instance, go to Routing → Contact flows → Create contact flow.
- Name it something like
Guava CSAT Task Flow. - Add a Set working queue block and point it at the queue you’d like surveys to be reviewed in (a CX or QA queue is a natural fit).
- Add a Transfer to queue block, then a Disconnect block.
- Save and publish the flow.
- Open the flow, click Show additional flow information, and copy the Contact flow ID (the UUID at the end of the ARN).
Tip: If you only want surveys to land somewhere queryable rather than being worked by a live agent, point the flow at a low-priority “review” queue — the task will still appear in Connect’s historical reports and contact search.
Step 3: Configure AWS Credentials
The example usesboto3, which reads credentials from the standard AWS credential chain. The easiest way for local development:
Step 4: Set Environment Variables
Step 5: Run the Example
+15559876543 with the customer’s phone number, set --name to their full name, and set --contact-id to the Amazon Connect ContactId of the original support call you’re following up on.
What to expect:
- Guava calls the customer and verifies they’re the right person
- Jamie asks if they have a minute for a quick survey
- If they decline, Jamie thanks them and ends the call gracefully — no pressure
- If they agree, Jamie collects an NPS score, asks whether the issue was resolved, and invites open-ended feedback
- The full survey result is printed as JSON to stdout and a Connect task is created linked to the original support contact via
RelatedContactId— so the response shows up in contact search and historical reports tied to the conversation it’s about - If no one picks up, Guava ends the call politely
How the Code Works
Defining the agent and starting the call
Agent is the top-level handle for the AI persona. call_phone places the call and binds the agent to that single conversation. The variables dict is passed into the call and made available to all handlers via call.get_variable(key) — here we pass the customer’s name (so Jamie can address them) and the original Connect ContactId (so the resulting survey task can be linked back to the support call it’s about).
Reaching the right person
reach_person handles the gatekeeper problem — Jamie confirms she’s speaking with the intended customer before starting the survey. If a family member or colleague answers, she politely asks for the right person. If the customer truly can’t be reached, outcome == "unavailable" and we end the call without leaving a long voicemail (post-hoc surveys are easy to skip; we don’t push them).
Asking permission, then collecting the survey
set_task gives Jamie a named objective and an ordered checklist. The first Field — willing_to_participate — is the gate. The remaining fields are marked required=False and the descriptions explicitly say “Only ask this if they agreed to participate” — so if the customer declines, Jamie doesn’t push them through the rest of the survey. The agent reads the prompts as guidance and adapts its phrasing rather than reciting them verbatim, so the conversation stays natural even though the schema is structured.
Honoring the customer’s choice
survey task completes, the @agent.on_task_complete("survey") handler runs. Customers respond with all kinds of phrasing — “sure”, “now’s not a great time”, “I’m driving”, “yeah I guess so” — so we use IntentRecognizer to map the free-text answer to a clean willing / not willing decision. If they declined, we end the call with a thank-you. The recognizer is instantiated once at module level and reused across calls.
Deriving the NPS category
Linking the survey back to the original contact
RelatedContactId — passing the original support call’s ContactId tells Amazon Connect to link the new survey task to that conversation. In Connect’s contact search, you can pivot from the support call to its survey task (and back) without joining tables yourself, and historical metrics that group by RelatedContactId will see them as a single customer interaction with a follow-up survey attached.
The Attributes dict is searchable in Connect’s contact search — putting nps_score, nps_category, and issue_resolved here means CX leaders can filter and report on surveys directly inside the Connect console.
Customization Ideas
Trigger surveys automatically after every support call Instead of running this script manually, hook it into your support flow: after a Connect contact ends, fire a Lambda (via EventBridge onAmazon Connect Contact Events) that pulls the customer’s name and phone from your CRM and invokes this example with the original ContactId. Surveys go out within minutes of the call ending, while the experience is fresh.
Sample only a fraction of calls
Calling every customer is overkill — most teams sample 10–20% of contacts. Add a random gate before invoking this script:
print(json.dumps(results, indent=2)) line with a write to your warehouse of choice (BigQuery, Snowflake, Redshift) or push to S3 in JSON Lines for downstream analytics — the Connect task gives you the operational view, the warehouse gives you the analytical view.
Customize the survey per product line
Pass a product_line variable into the call and conditionally include extra fields in the checklist — e.g., apparel customers get asked about fit and sizing, footwear customers get asked about comfort and durability. The same agent persona can run very different surveys depending on what the customer just bought.