{"slug": "creating-a-website-chat-widget-with-gradio-part-iv", "title": "Creating a Website Chat Widget with Gradio Part IV", "summary": "A website owner reports that their Gradio-powered AI chatbot widget stopped working due to a CORS policy change in Gradio, which now requires the 'Access-Control-Allow-Credentials' header to be 'true'. The user seeks a solution other than rewriting code to bypass CORS.", "body_md": "A while back [@John6666](https://discuss.huggingface.co/u/john6666) help set up an AI gradio chatbot on my website. Everything was working fine, with the AI chatbot doing a great job.\n\nHowever, I’ve not been monitoring it, and sometime recently(?) it stopped working. The problem is on the client I get the error:\n\nAccess to fetch at [huggingfacespace] from origin [mywebsite] has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The value of the ‘Access-Control-Allow-Credentials’ header in the response is ‘’ which must be ‘true’ when the request’s credentials mode is ‘include’.\n\nAfter looking around this seems to be related to a change to gradio where they fixed a security issue with CORS. However, the solution I found appeared to suggest the fix was to basically re-write the code to “get around” CORS rather than using it.\n\nIt that really the only solution?\n\nThis is the code that was working before the “fix” broke it:\n\n(website client code)\n\n``` js\n<script type=\"module\">\n    import { Client } from \"https://cdn.jsdelivr.net/npm/@gradio/client@/dist/index.min.js\";\n    import { marked } from \"https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js\";\n    \n    async function initChatWidget() {\n        const client = await Client.connect(\"https://[myspace].hf.space/\");\n        \n        const conversationId = crypto.randomUUID();                         // NEW FOR LOGGING\n        const chatToggle = document.getElementById('chat-toggle');\n        const chatContainer = document.getElementById('chat-container');\n        const closeChat = document.getElementById('close-chat');\n        const chatInput = document.getElementById('chat-input');\n        const sendButton = document.getElementById('send-message');\n        const messagesContainer = document.getElementById('chat-messages');\n    \n        chatToggle.addEventListener('click', () => {\n            chatContainer.classList.remove('hidden');\n        });\n    \n        closeChat.addEventListener('click', () => {\n            chatContainer.classList.add('hidden');\n        });\n    \n        // Auto-open chat on contact page\nif (window.location.pathname.includes('/contact') ||\n    window.location.pathname.endsWith('/contact.html') ||\n    window.location.pathname.includes('/account') ||\n    window.location.pathname.endsWith('/account.html')) {\n    chatContainer.classList.remove('hidden');\n}\n    \n        function appendMessage(text, sender) {\n            const div = document.createElement(\"div\");\n            div.className = `message ${sender}-message`;\n            div.textContent = text;  // or marked.parse(text) if you're using marked\n            messagesContainer.appendChild(div);\n            messagesContainer.scrollTop = messagesContainer.scrollHeight;\n        }\n    \n        async function sendMessage() {\n            const userMessage = chatInput.value.trim();\n            if (!userMessage) return;\n\n            appendMessage(userMessage, 'user');\n            chatInput.value = '';\n\n            try {\n                const result = await client.predict(\"/chat\", {\n                    message: {\"text\": userMessage, \"files\": []},\n                conversation_id: conversationId,                        // NEW FOR LOGGING\n                });\n\n      const lines = result.data[0];             // list of strings from Python\n      const botMessage = Array.isArray(lines) ? lines.join(\"\\n\") : String(lines);\n      appendMessage(botMessage, \"bot\");\n            \n            } catch (error) {\n                console.error('Error:', error);\n                appendMessage('Sorry, there was an error processing your request.', 'bot');\n            }\n        }\n \n        sendButton.addEventListener('click', sendMessage);\n        chatInput.addEventListener('keypress', (e) => {\n            if (e.key === 'Enter') sendMessage();\n        });\n    \n      // PRE-SEED: show a bot greeting as soon as the widget is ready\n      appendMessage(\"Hey there! What can I help you with today?\", \"bot\");\n      }\n    \n      initChatWidget();\n</script>\n```\n\n(code on huggingface space)\n\n``` python\nimport json\nimport requests # for API code\nimport holidays # details of UK holidays\nfrom datetime import datetime, timedelta, date, time\nfrom openai import OpenAI\nimport gradio as gr\nimport os\nimport uuid\n\nsay_hello = [\n    {\n        \"role\": \"assistant\",\n        \"content\": \"Hey there! What can I help you with today?\",\n    }\n]\n\n# This is the main chat code called by Gradio ChatInterface on user input, sends input to AI, processes response, returns to the Gradio ChatInterface\ndef chat(message, history, conversation_id):\n    if not conversation_id:\n        conversation_id = str(uuid.uuid4())\n\n    if isinstance(message, dict): # make sure the user comment is in an acceptable format, and convert to a string\n        user_text = message.get(\"text\", \"\")\n    else:\n        user_text = str(message)\n    history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history] # clean history for some non openai models\n    messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": user_text}] # illusion of memory\n    response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n\n    # AI STUFF HERE\n\n    response_as_a_list = [response.choices[0].message.content] # need to change reponse from string to a list of strings for the chatbot widget\n    return response_as_a_list\n\n# Additional (hidden) input so ChatInterface exposes 'conversation_id'\nconversation_id_input = gr.Textbox(\n    label=\"conversation_id\",\n    visible=False,\n    value=\"\",\n)\n\n# Use the Gradio Chatbot component to preload the chat (and history) with an initial greeting, rather than letting the user go first\nchatbot = gr.Chatbot(\n    value=say_hello,\n    type=\"messages\",\n)\n\n# The main chat interface handled by Gradio\nmy_chat = gr.ChatInterface(\n    fn=chat,\n    type=\"messages\",\n    multimodal=True,\n    title=\"Widget Demo Bot\",\n    api_name=\"chat\",\n    additional_inputs=[conversation_id_input],  # extra arg to fn\n)\n\nif __name__ == \"__main__\": \n    my_chat.launch(ssr_mode=False)\n```\n\n", "url": "https://wpnews.pro/news/creating-a-website-chat-widget-with-gradio-part-iv", "canonical_source": "https://discuss.huggingface.co/t/creating-a-website-chat-widget-with-gradio-part-iv/177208#post_1", "published_at": "2026-06-28 10:16:50+00:00", "updated_at": "2026-06-28 10:41:58.034932+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools"], "entities": ["Gradio", "Hugging Face", "John6666"], "alternates": {"html": "https://wpnews.pro/news/creating-a-website-chat-widget-with-gradio-part-iv", "markdown": "https://wpnews.pro/news/creating-a-website-chat-widget-with-gradio-part-iv.md", "text": "https://wpnews.pro/news/creating-a-website-chat-widget-with-gradio-part-iv.txt", "jsonld": "https://wpnews.pro/news/creating-a-website-chat-widget-with-gradio-part-iv.jsonld"}}