Skip to content
  • There are no suggestions because the search field is empty.

How to Install Q-share on your website (server-side: Node.js, PHP, Python)

Q-share publishes your hotel's information from Q-data (check-in times, prices, services, menus…) on your own website. Your server asks Q-share for the values once, caches them, and writes them into the page before it is sent to the visitor. When the hotel updates Q-data, your website updates too, with no manual copy-paste. This article is for the person who maintains the hotel's website. It takes about an hour for a first page

 What you need

  • Your Q-share licence, for example 9hwWs-SqXd. It is written in your installation workbook (sheet 4). Each hotel has its own licence.
  • Your installation workbook (Q-share_Catalogue_<Hotel>.xlsx), sent by your Quinta contact. It lists every datapoint you can publish, the ones your website is missing, and ready-to-paste code.
  • A server that renders your pages with one of:
    • Node.js 18 or later (built-in fetch; Node 18 prints a harmless "ExperimentalWarning: The Fetch API is an experimental feature"). The example uses top-level await, so run it as an ES module (.mjs file or "type": "module" in package.json), or call getQSharePoints() inside an async function.
    • PHP 7.4 or later, with cURL or allow_url_fopen. Keep the protocol_version => 1.1 line: without cURL, PHP 7 sends HTTP/1.0 requests, which Q-share refuses (error 426).
    • Python 3 with the requests package
  • Outbound HTTPS from your server to q-share.quinta.im.

How it works

  1. Your server sends one request to https://q-share.quinta.im/points with your licence, a language and the list of datapoints (points) the page needs.
  2. Q-share answers with the final, translated text for each datapoint, for example "11-01.time": "14:00".
  3. Your server caches the answer for 5–15 minutes and places each value in the page template.

Because the values are in the HTML your server sends, visitors, search engines and AI assistants all see them without running any JavaScript.

Step 1 – Choose the datapoints to publish

Every datapoint has an ID made of a dialog code and a field, for example 11-01.time (check-in time) or 13-01.guestsAllVehiclesFees (parking price). Take the IDs from your workbook only; never type or guess an ID.

Workbook sheet Use it to
1. Q-data datapoints Find any datapoint. Use only rows marked OK in the "Use" column; rows marked "DO NOT USE" are empty, placeholders or internal.
2. Website gaps Start here. Topics guests ask about most that are missing or different on your website, ranked High / Medium / Low. Each row has a ready "Points string".
3. Warm data Values that change often (hours, prices, menus). These gain the most from being synced automatically.
4. SSR scripts The complete Node.js, PHP and Python scripts with your licence already filled in.

Rows with status "Different" mean your website and Q-data disagree today. Ask your Quinta contact which one is right before you publish them.

Step 2 – Add the script to your server

Copy the script for your language from sheet 4 of the workbook. The examples below show the structure; replace YOUR_LICENCE and the points list with your own.

Node.js

// Node.js 18+ — native fetch, no dependency needed. const params = new URLSearchParams({   license: 'YOUR_LICENCE',   lang: 'en',   // Datapoint IDs from your workbook:   points: '11-01.time,11-11.time,12-01.from,12-01.to,13-01.guestsAllVehiclesFees',   // Format parameters (required for time / date / staff-language datapoints):   'type_11-01.time': 'time',   'type_11-11.time': 'time',   'type_12-01.from': 'time',   'type_12-01.to': 'time', })  async function getQSharePoints() {   try {     const res = await fetch(`https://q-share.quinta.im/points?${params}`, {       headers: { 'x-source': 'qshare-ssr-node' },       signal: AbortSignal.timeout(10_000),     })     if (!res.ok) throw new Error(`Q-Share responded ${res.status}`)     const { points } = await res.json()     return points   } catch {     // Never let a Q-Share outage break your page.     return {}   } }  // Cache the result server-side (5-15 min) — do not call per page-view. const points = await getQSharePoints()  // Escape values before placing them in HTML: const escapeHtml = (s) => String(s).replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]))

PHP

<?php $params = http_build_query([   'license' => 'YOUR_LICENCE',   'lang'    => 'en',   'points'  => '11-01.time,11-11.time,12-01.from,12-01.to,13-01.guestsAllVehiclesFees',   'type_11-01.time' => 'time',   'type_11-11.time' => 'time',   'type_12-01.from' => 'time',   'type_12-01.to'   => 'time', ]); $endpoint = 'https://q-share.quinta.im/points?' . $params;  // cURL first (works without allow_url_fopen), file_get_contents fallback. function qshare_fetch_points($url) {   if (function_exists('curl_init')) {     $ch = curl_init($url);     curl_setopt_array($ch, [       CURLOPT_RETURNTRANSFER => true,       CURLOPT_FOLLOWLOCATION => true,       CURLOPT_TIMEOUT        => 10,       CURLOPT_HTTPHEADER     => ['x-source: qshare-ssr-php'],     ]);     $body = curl_exec($ch);     $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);     curl_close($ch);     return ($body !== false && $code >= 200 && $code < 300) ? $body : null;   }   $ctx = stream_context_create(['http' => [     'header'  => "x-source: qshare-ssr-php\r\n",     'timeout' => 10,     'protocol_version' => 1.1,  // PHP 7.x defaults to HTTP/1.0, which Q-share refuses (426)   ]]);   return @file_get_contents($url, false, $ctx) ?: null; }  // Cache the result server-side (5-15 min) — do not call per page-view. $raw = qshare_fetch_points($endpoint); $points = $raw ? (json_decode($raw, true)['points'] ?? []) : [];

Python

# Python 3 — pip install requests import requests  def get_qshare_points():     try:         response = requests.get(             'https://q-share.quinta.im/points',             params={                 'license': 'YOUR_LICENCE',                 'lang': 'en',                 'points': '11-01.time,11-11.time,12-01.from,12-01.to,13-01.guestsAllVehiclesFees',                 'type_11-01.time': 'time',                 'type_11-11.time': 'time',                 'type_12-01.from': 'time',                 'type_12-01.to': 'time',             },             headers={'x-source': 'qshare-ssr-py'},             timeout=10,         )         response.raise_for_status()         return response.json().get('points', {})     except requests.RequestException:         # Never let a Q-Share outage break your page.         return {}  # Cache the result server-side (5-15 min) — do not call per page-view. points = get_qshare_points()Step 3 – Keep the type_ lines

Some datapoints need a format parameter, written type_<ID>. The workbook gives the exact line for each one (columns "type_ – Node/Python" and "type_ – PHP"). Without it you get raw values:

Datapoint type Without type_ With type_
Staff / TV languages (staff-spoken) EN, IT, ES English, Italian, Spanish
Dates (date, date-range) 2026-04-01T00:00:00.000Z 2026-04-01
Times (time) 14:00 14:00

The snippets shown in the Quinta Console do not include these lines yet. Always use the lines from your workbook.

Step 4 – Place the values in your page

Each value is a finished, translated string. Put it where the information belongs on the page, and always escape it as HTML. The workbook gives the placeholder for every datapoint:

Language Placeholder
Node.js (template literal) ${escapeHtml(points['11-01.time'] ?? '')}
PHP <?= htmlspecialchars($points['11-01.time'] ?? '') ?>
Python (f-string, import html) {html.escape(points.get('11-01.time', ''))}

Example (PHP):

<p>Check-in from <?= htmlspecialchars($points['11-01.time'] ?? '') ?>, check-out by <?= htmlspecialchars($points['11-11.time'] ?? '') ?>.</p>
  • Some values span several lines. Give their container the CSS rule white-space: pre-line.
  • Some values include their own label, for example "Late check-out: Yes". Check the live value in the workbook before writing text around it.
  • Keep a sensible fallback: if a value is empty, the ?? '' leaves the space blank instead of breaking the page.
Step 5 – One request per language

Send one request per language version of your website and change only lang (en, it, fr, de, es, pt…). The datapoint IDs and placeholders stay the same.

Missing translations fall back to English. If a text has not been translated in Q-data, or the language code is not supported, Q-share returns the English text without an error. Check each language version of the page and report English text to your Quinta contact.

Step 6 – Cache the answer
  • Q-share already caches answers for about 1 hour.
  • On your side, cache the result for 5–15 minutes per language. Never call Q-share on every page view.
  • Keep each request to about 200 datapoints (a URL of roughly 10 KB). Much longer requests are refused with error 431; split the list into several requests.
Step 7 – Test before going live
  1. Run the script once and print points. You should see one entry per ID you asked for.
  2. Compare a few values with sheet 2 or 3 of the workbook ("Live value" column).
  3. Check every language version of the page.
  4. Change the licence to a wrong value and reload: the page must still load, with the Q-share values left blank.
  5. View the page source (not the inspector) and confirm the values are in the HTML.
Troubleshooting
What you see Likely cause What to do
All values blank Wrong licence, server can't reach q-share.quinta.im, or timeout. Check the licence in sheet 4. Test curl "https://q-share.quinta.im/points?license=YOUR_LICENCE&lang=en&points=10-02.starsRates" from the server. A wrong licence returns an error (HTTP 500).
The values belong to another hotel The licence was copied from the Console while another hotel was selected. Use the licence from your workbook, or ask your Quinta contact.
One value blank The ID has a typo, or the field is empty in Q-data. Copy the ID from the workbook again. If it is still empty, tell your Quinta contact.
"EN, IT" instead of "English, Italian", or a date with "T00:00:00.000Z" The type_ line is missing. Add the type_ line from the workbook (Step 3).
A value is out of date Caching (Q-share ~1 h + your cache). Wait for the caches to expire, or clear your own cache.
Text runs together on one line Multi-line value. Add white-space: pre-line to the element.
PHP: all values blank, error 426 "Upgrade Required" in the logs PHP 7 without cURL sends HTTP/1.0. Add 'protocol_version' => 1.1 to the stream context (it is in the sheet-4 script), or enable cURL.
Error 431 "Request Header Fields Too Large" Too many datapoints in one URL. Split into requests of about 200 datapoints.
English text on a non-English page The text is not translated in Q-data (Q-share falls back to English). Tell your Quinta contact which datapoints are affected.
SyntaxError: await is only valid in async functions (Node.js) The file runs as CommonJS. Rename it to .mjs, add "type": "module", or wrap the call in an async function.
API reference
Item Value
Endpoint GET https://q-share.quinta.im/points
license Your hotel's Q-share licence (required)
lang Language code, e.g. en, it (required)
points Comma-separated datapoint IDs (required)
type_<ID> Format of a datapoint, e.g. time, date-range, staff-spoken, source-label
Header x-source qshare-ssr-node, qshare-ssr-php or qshare-ssr-py
Response {"points": {"11-01.time": "14:00", …}, "metadata": {"cache": {"ttl": 3600}}}
Frequently asked questions

Who updates the content?

The hotel, in Q-data, with help from Quinta. You don't need to change your code when a price or an opening time changes.

Can I use Q-share without server-side code?

Yes. A client-side alternative (a script tag plus <div data-point="…"> elements) is listed in sheet 1 of the workbook ("Client-side tag" column). Values are then filled in by JavaScript in the browser, so they are not in the HTML your server sends.

What happens if Q-share is unavailable?

The scripts give up after a 10-second timeout and return an empty result, so your page loads without those values. Keep your cached copy to show the last known values.

Is any personal data sent?

The request contains only your licence, a language and datapoint IDs. No visitor data is sent, because the call comes from your server, not from the visitor's browser.

Need help? Contact your Quinta account manager with your hotel name and a copy of the request you are sending.