How to Access Participant Attributes Set by Web Messaging Inside an Architect Inbound Message Flow
What You Will Build
- You will build a Python script that queries the Genesys Cloud API to retrieve inbound message transcripts, specifically extracting custom participant attributes injected via the Web Messaging SDK.
- This tutorial uses the Genesys Cloud
PureCloudPlatformClientV2Python SDK and the/api/v2/analytics/conversations/details/queryendpoint. - The programming language covered is Python 3.9+.
Prerequisites
- OAuth Client Type: A Genesys Cloud OAuth Client ID and Secret with the
apigrant type. - Required Scopes:
analytics:conversation:read,webchat:read,messages:read. - SDK Version:
genesys-cloud-purecloud-platform-clientversion 130.0.0 or higher. - Language/Runtime: Python 3.9+ with
venvsupport. - External Dependencies:
genesys-cloud-purecloud-platform-clientpython-dotenv(for secure credential management)
Authentication Setup
Genesys Cloud uses OAuth 2.0 for API authentication. For server-to-server integrations like this script, you will use the Client Credentials flow. The SDK handles the token retrieval and refresh automatically, but you must provide the correct credentials and environment.
Create a .env file in your project root with the following content:
GENESYS_CLOUD_REGION="mypurecloud.com"
GENESYS_CLOUD_CLIENT_ID="your_client_id_here"
GENESYS_CLOUD_CLIENT_SECRET="your_client_secret_here"
Install the required packages:
pip install genesys-cloud-purecloud-platform-client python-dotenv
Initialize the SDK client in your Python script. This object will be used for all subsequent API calls.
import os
from dotenv import load_dotenv
from purecloud_platform_client import Configuration, ApiClient, PureCloudAuth
# Load environment variables
load_dotenv()
def get_authenticated_client():
"""
Initializes and returns an authenticated PureCloud Platform Client.
"""
region = os.getenv("GENESYS_CLOUD_REGION", "mypurecloud.com")
client_id = os.getenv("GENESYS_CLOUD_CLIENT_ID")
client_secret = os.getenv("GENESYS_CLOUD_CLIENT_SECRET")
if not client_id or not client_secret:
raise ValueError("GENESYS_CLOUD_CLIENT_ID and GENESYS_CLOUD_CLIENT_SECRET must be set in .env")
# Configure the OAuth client
auth_config = PureCloudAuth(client_id, client_secret, region)
# Create the API client with the auth configuration
api_client = ApiClient(configuration=Configuration(oauth2_client=auth_config))
return api_client
if __name__ == "__main__":
try:
client = get_authenticated_client()
print("Authentication successful.")
except Exception as e:
print(f"Authentication failed: {e}")
Implementation
Step 1: Query Conversations with Participant Attributes
The core challenge in accessing participant attributes is that they are not always returned in the standard conversation summary. You must explicitly request them using the analytics/conversations/details/query endpoint. This endpoint allows you to define a filter for conversations and specify which details to return.
To access attributes set by the Web Messaging SDK (e.g., via genesys.cloud.webchat.setParticipantAttribute), you need to query for webchat type conversations and ensure the response includes participant details.
from purecloud_platform_client.rest import ApiException
from purecloud_platform_client.models import ConversationQueryRequest, ConversationQueryResult
def query_recent_webchat_conversations(api_client):
"""
Queries the last 10 Webchat conversations to find those with participant attributes.
"""
analytics_api = api_client.analytics_api
# Define the query parameters
# We filter by type 'webchat' and order by start time descending
body = ConversationQueryRequest(
size=10,
filter=ConversationQueryRequest.Filter(
conversation_type=["webchat"],
date_range_type="start"
),
order_by="start",
order="desc",
# Critical: Request participant details to see attributes
view="full"
)
try:
# Execute the query
response = analytics_api.post_analytics_conversations_details_query(body=body)
return response
except ApiException as e:
print(f"Exception when calling AnalyticsApi->post_analytics_conversations_details_query: {e}")
raise
if __name__ == "__main__":
client = get_authenticated_client()
result = query_recent_webchat_conversations(client)
if result and result.conversations:
print(f"Found {len(result.conversations)} conversations.")
else:
print("No conversations found.")
Step 2: Extracting Custom Participant Attributes
The response object contains a list of conversations. Each conversation has a participants array. Within each participant object, you will find an attributes dictionary. This is where custom attributes set via the Web Messaging SDK are stored.
Attributes set via the SDK are typically prefixed with custom: or are simply key-value pairs depending on how they were set. The Web Messaging SDK allows setting attributes that are persisted to the participant profile.
def extract_participant_attributes(conversation):
"""
Extracts and prints custom attributes for all participants in a conversation.
"""
print(f"\n--- Conversation ID: {conversation.id} ---")
if not conversation.participants:
print("No participants found.")
return
for participant in conversation.participants:
# Identify if this is the customer (typically not associated with a user ID in webchat)
is_customer = participant.user is None or participant.user.id is None
participant_type = "Customer" if is_customer else f"Agent ({participant.user.name})"
print(f"Participant: {participant_type} (ID: {participant.id})")
if participant.attributes:
# Filter for custom attributes
# Genesys Cloud often prefixes custom attributes, but SDK-set ones might be raw keys
custom_attrs = {k: v for k, v in participant.attributes.items() if not k.startswith("system:")}
if custom_attrs:
print(f" Custom Attributes: {custom_attrs}")
else:
print(" No custom attributes found.")
else:
print(" No attributes object found.")
Step 3: Processing Results and Handling Pagination
The post_analytics_conversations_details_query endpoint supports pagination. If you need to process more than 10 conversations, you must use the next_page token provided in the response.
Additionally, you should handle cases where the conversation is still active or if the attributes are not yet propagated. Analytics data can have a slight delay (typically < 5 seconds) after the attribute is set.
def process_all_conversations(api_client, max_pages=3):
"""
Processes conversations with pagination support.
"""
page_count = 0
next_page_token = None
while page_count < max_pages:
# Construct the query
body = ConversationQueryRequest(
size=10,
filter=ConversationQueryRequest.Filter(
conversation_type=["webchat"],
date_range_type="start"
),
order_by="start",
order="desc",
view="full"
)
# Add pagination token if available
if next_page_token:
body.page_token = next_page_token
try:
response = api_client.analytics_api.post_analytics_conversations_details_query(body=body)
if not response.conversations:
print("No more conversations to process.")
break
for conversation in response.conversations:
extract_participant_attributes(conversation)
# Check for next page
next_page_token = response.next_page
page_count += 1
if not next_page_token:
print("End of results.")
break
except ApiException as e:
print(f"API Error on page {page_count}: {e}")
break
if __name__ == "__main__":
client = get_authenticated_client()
process_all_conversations(client)
Complete Working Example
The following script combines authentication, querying, and attribute extraction into a single runnable module.
import os
import sys
from dotenv import load_dotenv
from purecloud_platform_client import Configuration, ApiClient, PureCloudAuth
from purecloud_platform_client.rest import ApiException
from purecloud_platform_client.models import ConversationQueryRequest
# Load environment variables
load_dotenv()
def get_authenticated_client():
"""
Initializes and returns an authenticated PureCloud Platform Client.
"""
region = os.getenv("GENESYS_CLOUD_REGION", "mypurecloud.com")
client_id = os.getenv("GENESYS_CLOUD_CLIENT_ID")
client_secret = os.getenv("GENESYS_CLOUD_CLIENT_SECRET")
if not client_id or not client_secret:
raise ValueError("GENESYS_CLOUD_CLIENT_ID and GENESYS_CLOUD_CLIENT_SECRET must be set in .env")
auth_config = PureCloudAuth(client_id, client_secret, region)
api_client = ApiClient(configuration=Configuration(oauth2_client=auth_config))
return api_client
def extract_participant_attributes(conversation):
"""
Extracts and prints custom attributes for all participants in a conversation.
"""
print(f"\n--- Conversation ID: {conversation.id} ---")
if not conversation.participants:
print("No participants found.")
return
for participant in conversation.participants:
is_customer = participant.user is None or participant.user.id is None
participant_type = "Customer" if is_customer else f"Agent ({participant.user.name})"
print(f"Participant: {participant_type} (ID: {participant.id})")
if participant.attributes:
# Filter out system attributes if desired, or inspect all
custom_attrs = {k: v for k, v in participant.attributes.items() if not k.startswith("system:")}
if custom_attrs:
print(f" Custom Attributes: {custom_attrs}")
else:
print(" No custom attributes found.")
else:
print(" No attributes object found.")
def process_conversations(api_client, max_pages=2):
"""
Queries and processes webchat conversations.
"""
page_count = 0
next_page_token = None
while page_count < max_pages:
body = ConversationQueryRequest(
size=10,
filter=ConversationQueryRequest.Filter(
conversation_type=["webchat"],
date_range_type="start"
),
order_by="start",
order="desc",
view="full"
)
if next_page_token:
body.page_token = next_page_token
try:
response = api_client.analytics_api.post_analytics_conversations_details_query(body=body)
if not response.conversations:
print("No more conversations to process.")
break
for conversation in response.conversations:
extract_participant_attributes(conversation)
next_page_token = response.next_page
page_count += 1
if not next_page_token:
print("End of results.")
break
except ApiException as e:
print(f"API Error on page {page_count}: {e}")
break
if __name__ == "__main__":
try:
client = get_authenticated_client()
print("Authentication successful. Fetching conversations...")
process_conversations(client)
except Exception as e:
print(f"Fatal error: {e}")
sys.exit(1)
Common Errors & Debugging
Error: 401 Unauthorized
- Cause: The OAuth token is expired, invalid, or the client credentials are incorrect.
- Fix: Verify your
GENESYS_CLOUD_CLIENT_IDandGENESYS_CLOUD_CLIENT_SECRETin the.envfile. Ensure the region is correct. The SDK handles token refresh, so this usually indicates a credential mismatch.
Error: 403 Forbidden
- Cause: The OAuth client lacks the necessary scopes.
- Fix: In the Genesys Cloud Admin portal, navigate to Admin > Security > OAuth Clients. Edit your client and ensure the following scopes are added:
analytics:conversation:readwebchat:readmessages:read
- Restart your script after updating scopes.
Error: Participant Attributes Not Populated
- Cause: The attributes were set in the Web Messaging SDK but have not yet propagated to the analytics database, or the query view is not
full. - Fix:
- Ensure
view="full"is set in theConversationQueryRequest. - Wait a few seconds after setting the attribute in the UI before querying.
- Verify the attribute key name. If you used
genesys.cloud.webchat.setParticipantAttribute('myKey', 'myValue'), the key in the API response will bemyKey.
- Ensure
Error: 429 Too Many Requests
- Cause: You have exceeded the API rate limit.
- Fix: Implement exponential backoff. The Python SDK does not handle retries automatically for all methods, so you may need to wrap the API call in a retry loop.
import time
def query_with_retry(api_client, body, max_retries=3):
for attempt in range(max_retries):
try:
return api_client.analytics_api.post_analytics_conversations_details_query(body=body)
except ApiException as e:
if e.status == 429:
wait_time = (2 ** attempt) + 1
print(f"Rate limited. Retrying in {wait_time} seconds...")
time.sleep(wait_time)
else:
raise
raise Exception("Max retries exceeded for 429 error")