Skip to content

Instantly share code, notes, and snippets.

@nitefood
Last active September 7, 2025 19:09
Show Gist options
  • Save nitefood/e2813b900692f0ec3ed1c42e3c3a6767 to your computer and use it in GitHub Desktop.
Save nitefood/e2813b900692f0ec3ed1c42e3c3a6767 to your computer and use it in GitHub Desktop.
How to Connect Alexa to Gemini: A Step-by-Step Guide Using n8n

Step-by-Step Setup

  1. Access the Alexa Developer Console: Go to https://developer.amazon.com/alexa/console/ask.
  2. Create a New Skill: Click on Create Skill, give it a name, and choose your preferred language.
  3. Choose a Template: Select the "Start from Scratch" template and leave the rest as the default.

Configure the Skill

Once your skill is created, you will be taken to the dashboard. Here's what you need to configure:

  • Skill Invocation Name: This is the word or phrase you'll use to open your skill. It's what you say to your Echo device (e.g., "Alexa, open my awesome assistant"). This command launches the skill, which in turn runs your n8n workflow and starts a conversation with Gemini.

  • Interaction Model -> Intents: This is where you define what actions your skill can perform.

    • You can delete the default HelloWorldIntent.
    • Click Add intent to create a new one.
    • Name the new intent LLMIntent and click Create custom intent.
  • Configure the Intent Slot: A slot is a variable that captures information from the user's request.

    • In the LLMIntent settings, scroll down to the Intent Slots section and click the plus icon to add a new slot.
    • Name this slot question.
    • Set the Slot Type to AMAZON.SearchQuery. This type is perfect for capturing open-ended questions.
    • Click Edit Dialog and enable the "Is this slot required to fulfill the intent?" selector. This ensures Alexa will prompt the user if they don't provide a question.
  • Add Utterances: Utterances are the phrases that trigger your intent.

    • In the LLMIntent settings, go to the Sample Utterances section.
    • Add a simple utterance like gemini {question}.
    • This setup means that when your skill is active, you'll need to start your questions with "gemini." For example: "Alexa, open my awesome assistant... Gemini, what's the largest planet in the solar system?"
    • Pro-Tip: If you want to avoid saying "gemini" for every question, you'll need to add more utterances to cover various conversation starters, like tell me {question}, ask {question}, what {question}, and so on.

n8n Configuration

To handle the conversation and interface with Gemini, you will need to import a pre-made n8n workflow.

  1. Download the Workflow: Download the workflow JSON below.
  2. Import to n8n: In your n8n instance, click the New button in the top-left corner, and then select Import from File. Upload the JSON file you just downloaded.
  3. Configure Credentials: The imported workflow will require you to add your Gemini API key. Double-click the Gemini node to open its settings and add your credentials.
  4. More Customizations: Optionally, you can customize the SearXNG, Calendar and Telegram tools to integrate them within the workflow, but that's not strictly required (although it can be very useful for your AI Agent to have Internet, calendar and Telegram to interact with).

Connect the skill to n8n

The last step is to connect your Alexa skill to your n8n workflow.

  • In the left-hand sidebar of the Alexa developer console, click on Endpoint.
  • Select the HTTPS radio button.
  • In the Default Region field, paste the production webhook URL from your n8n instance. Make sure you've activated the workflow in n8n first!
  • Select the option "My development endpoint has a certificate from a trusted certificate authority" (this is the standard for most n8n setups).
  • Finally, click Save and then Build at the top of the page.
{
"name": "Alexa-Gemini",
"nodes": [
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"version\": \"1.0\",\n \"sessionAttributes\": {\n \"countActionList\": {\n \"read\": true,\n \"category\": true\n }\n }{{ (typeof $json.response !== 'undefined' && $json.response !== null) ? ',\"response\": ' + JSON.stringify($json.response) : '' }}\n}",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.4,
"position": [
1216,
32
],
"id": "441a9b83-850d-43bc-b5a0-95a6ab669ebe",
"name": "Respond to Webhook"
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"leftValue": "={{ $json.body.request.type }}",
"rightValue": "LaunchRequest",
"operator": {
"type": "string",
"operation": "equals"
},
"id": "cb591d54-51db-475e-8f75-aa17b008a875"
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "60b2e95d-b0e1-4fd5-bfd3-2acc0e196b0c",
"leftValue": "={{ $json.body.request.type }}",
"rightValue": "SessionEndedRequest",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "7ba00338-55f1-4039-809a-89f137d3969b",
"leftValue": "={{ $json.body.request.type }}",
"rightValue": "IntentRequest",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
}
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
-160,
0
],
"id": "40d76e47-c8ae-46d8-a8d5-7aaf9aa1b496",
"name": "Request type Router"
},
{
"parameters": {
"promptType": "define",
"text": "=The user request is the following:\n\n```\n\n{{ $json.body.request.intent.slots.question.value }}\n\n```\n\nIf needed, remember that the current date and time are: {{ $now.toISO() }}.\n",
"options": {
"systemMessage": "=You are a friendly and versatile assistant. You have a vast knowledge of any topic. The user might mix questions about the tools you have available, but also mix them with generic questions, always try to understand the context and do not take the user's intent for granted.\nAlways respond in an exhaustive, friendly and concise manner. Follow the following output guidelines:\n\n# IMPORTANT: OUTPUT GUIDELINES\n\n- Interactions with the user will happen through voice-controlled devices, so do not use emojis and special formatting\n- Respond using only text that is easy to convey in audio format (TTS) in response to the user\n- NEVER use the characters `\\n` (new line) and `\"`, otherwise this will invalidate the output. The text must be extremely simple to embed in a JSON string, and clear for subsequent reading by a TTS model."
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2.1,
"position": [
352,
352
],
"id": "e65ba76f-a112-46d0-b217-f3d66c9afb68",
"name": "AI Agent"
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
352,
544
],
"id": "32c018fe-1a56-4e8b-a519-b92a0ba84572",
"name": "Google Gemini Chat Model",
"credentials": {
"googlePalmApi": {
"id": "4cOR2QMoEXlCs0aI",
"name": "Google Gemini(PaLM) Api account"
}
}
},
{
"parameters": {
"sessionIdType": "customKey",
"sessionKey": "={{ $('Alexa Skill Webhook').item.json.body.session.sessionId }}",
"contextWindowLength": 10
},
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"typeVersion": 1.3,
"position": [
480,
512
],
"id": "9896b6d3-a787-4680-8d2f-49b000342874",
"name": "Simple Memory"
},
{
"parameters": {
"httpMethod": "POST",
"path": "c8fda81e-73c8-4ccf-b806-57756dedf947",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
-368,
16
],
"id": "fb45a6d9-baf6-4d3c-86c0-e44e4ea63ea1",
"name": "Alexa Skill Webhook",
"webhookId": "c8fda81e-73c8-4ccf-b806-57756dedf947"
},
{
"parameters": {
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n_Route the request according to the user's intent_",
"height": 272,
"width": 176,
"color": 5
},
"type": "n8n-nodes-base.stickyNote",
"position": [
48,
80
],
"typeVersion": 1,
"id": "79dbf154-ad3e-4739-adc4-8f2828736ced",
"name": "Sticky Note"
},
{
"parameters": {
"content": "_Handle skill Start / Stop and session close_",
"height": 592,
"width": 208
},
"type": "n8n-nodes-base.stickyNote",
"position": [
448,
-400
],
"typeVersion": 1,
"id": "3b88be09-335b-4dcc-99ca-3adb92eccf7e",
"name": "Sticky Note1"
},
{
"parameters": {
"content": "## Handle the LLM conversation intent",
"height": 480,
"width": 720,
"color": 4
},
"type": "n8n-nodes-base.stickyNote",
"position": [
304,
240
],
"typeVersion": 1,
"id": "1bde640b-291d-437c-96e5-ce0866bfcb94",
"name": "Sticky Note2"
},
{
"parameters": {
"content": "_Determine the request type (if the user has opened the skill, closed it, or wants to interact with the LLM)_",
"height": 288,
"width": 208,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"position": [
-208,
-96
],
"typeVersion": 1,
"id": "dfb4aff9-7768-4e14-b54c-03a839abae1f",
"name": "Sticky Note3"
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "ce1db873-0b88-4f1b-9458-d06ed274b539",
"leftValue": "={{ $json.body.request.intent.name }}",
"rightValue": "AMAZON.StopIntent",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "49394ba5-74df-4ba5-ba0e-33b761ce2c8f",
"leftValue": "={{ $json.body.request.intent.name }}",
"rightValue": "LLMIntent",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
}
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
80,
112
],
"id": "9e0cd4b2-20f2-4d71-a4f2-ac9fa6b7ce12",
"name": "Intent router"
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "={\n \"type\": \"SessionEndedRequest\",\n \"requestId\": \"{{ $json.body.request.requestId }}\",\n \"timestamp\": \"{{ $now.toISO() }}\",\n \"reason\": \"USER_INITIATED\"\n}",
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
496,
-160
],
"id": "a1cf3091-db6f-4fa4-a4e7-454a5c05cd52",
"name": "Set response fields (SessionEndedRequest)"
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "={\n \"response\": {\n \"outputSpeech\": {\n \"type\": \"PlainText\",\n \"text\": \"{{ $json.output }}\"\n },\n \"card\": {\n \"type\": \"Simple\",\n \"title\": \"Reply from Gemini\",\n \"content\": \"{{ $json.output }}\"\n },\n \"reprompt\": {\n \"outputSpeech\": {\n \"type\": \"PlainText\",\n \"text\": \"start your sentence with: \\\"gemini\\\", to ask a question\"\n }\n },\n \"shouldEndSession\": false\n }\n}",
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
880,
352
],
"id": "1084f95c-833a-4615-b680-45577c8f2021",
"name": "Set response fields (LLMIntent)"
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "={\n \"response\": {\n \"outputSpeech\": {\n \"type\": \"PlainText\",\n \"text\": \"Bye bye!\"\n }\n },\n \"shouldEndSession\": false\n}",
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
496,
16
],
"id": "66357f3c-f00f-468a-bdf3-f224be52936e",
"name": "Set response fields (AMAZON.StopIntent)"
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "{\n \"response\": {\n \"outputSpeech\": {\n \"type\": \"PlainText\",\n \"text\": \"start your sentence with: \\\"gemini\\\", to ask a question\"\n },\n \"reprompt\": {\n \"outputSpeech\": {\n \"type\": \"PlainText\",\n \"text\": \"start your sentence with: \\\"gemini\\\", to ask a question\"\n }\n },\n \"shouldEndSession\": false\n }\n}",
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
496,
-336
],
"id": "84e91110-ad67-4271-ac20-cee1f43b0c15",
"name": "Set response fields (LaunchRequest)"
},
{
"parameters": {
"options": {
"safesearch": 0
}
},
"type": "@n8n/n8n-nodes-langchain.toolSearXng",
"typeVersion": 1,
"position": [
720,
560
],
"id": "12d9034a-1e28-4807-ab65-e6fd9339b476",
"name": "SearXNG",
"credentials": {
"searXngApi": {
"id": "kVIfIc15vsCQvMAm",
"name": "Your SearXNG Instance"
}
}
},
{
"parameters": {
"sseEndpoint": "http://127.0.0.1:5678/mcp/04f71579-6b7b-49cb-8ef7-db29d3189ab2"
},
"type": "@n8n/n8n-nodes-langchain.mcpClientTool",
"typeVersion": 1,
"position": [
608,
544
],
"id": "a5a4b1f2-09ea-4a61-94db-244bc0eadb1a",
"name": "Calendar MCP Client"
},
{
"parameters": {
"jsCode": "let text = $input.first().json.output;\n\n// Escape double quotes\ntext = text.replace(/\"/g, '\\\\\"');\n\n// Remove linefeeds\ntext = text.replace(/\\n/g, '');\n\n// Replace the original text\n$input.first().json.output = text;\n\nreturn $input.all();"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
704,
352
],
"id": "f4eda107-c41c-4c76-8ac2-03d99f4ea008",
"name": "Escape special chars"
},
{
"parameters": {
"chatId": "<YOUR-TELEGRAM-CHATID>",
"text": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Text', ``, 'string') }}",
"additionalFields": {
"appendAttribution": false
}
},
"type": "n8n-nodes-base.telegramTool",
"typeVersion": 1.2,
"position": [
864,
560
],
"id": "696ff64a-4997-4a53-8eb0-7bf42010e6a3",
"name": "Send a text message in Telegram",
"webhookId": "2888a723-f40e-4acd-ba67-c3a4abae0ff2",
"credentials": {
"telegramApi": {
"id": "7HEjUwbAQ1qdz5ao",
"name": "Telegram account"
}
}
}
],
"pinData": {},
"connections": {
"Request type Router": {
"main": [
[
{
"node": "Set response fields (LaunchRequest)",
"type": "main",
"index": 0
}
],
[
{
"node": "Set response fields (SessionEndedRequest)",
"type": "main",
"index": 0
}
],
[
{
"node": "Intent router",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI Agent": {
"main": [
[
{
"node": "Escape special chars",
"type": "main",
"index": 0
}
]
]
},
"Simple Memory": {
"ai_memory": [
[
{
"node": "AI Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Alexa Skill Webhook": {
"main": [
[
{
"node": "Request type Router",
"type": "main",
"index": 0
}
]
]
},
"Intent router": {
"main": [
[
{
"node": "Set response fields (AMAZON.StopIntent)",
"type": "main",
"index": 0
}
],
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Set response fields (SessionEndedRequest)": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Set response fields (LLMIntent)": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Set response fields (AMAZON.StopIntent)": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Set response fields (LaunchRequest)": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"SearXNG": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Calendar MCP Client": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Escape special chars": {
"main": [
[
{
"node": "Set response fields (LLMIntent)",
"type": "main",
"index": 0
}
]
]
},
"Send a text message in Telegram": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "a1e51c7b-0d10-44a1-b2e4-b20060167f76",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "6c0ae52c424bb304754dd36ddb4d5a27e72da7897a48a3fabdfb969b44861181"
},
"id": "UKLoxp3jvO3ALHFc",
"tags": []
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment