Use the ETA Buy Button to sell M Ride tickets on your website
Overview
The ETA Buy Button is a JavaScript widget that embeds a shuttle ticket purchasing flow into any webpage. Configuration is split across two places:
- The
<script>tag — global settings that apply to the entire widget instance (API endpoint, styling, callbacks) - Each
<button>tag — per-event settings that control what happens when a specific button is clicked
1. Install the Script Tag
Add the following <script> tag near the bottom of your <body>. The id must be exactly eta-buy-button.
<script id="eta-buy-button"
src="https://widget.mride.com/static/js/widget.js"
type="module"
data-trigger-class="shuttle-btn"
data-api-url="https://widget.mride.com/api/v1">
</script>
Script Tag Attributes
| Attribute | Required | Default | Description |
|---|---|---|---|
id |
Yes | — | Must be eta-buy-button. The widget will throw an error if this is missing. |
src |
Yes | — | URL to the widget JavaScript file. |
type |
Yes | — | Must be module. |
data-trigger-class |
No | shuttle-btn |
The CSS class the widget listens for click events on. Any button with this class will open the widget. |
data-root-element |
No | shuttle-widget |
The id given to the widget's root DOM element. Must be unique on the page. |
data-api-url |
No | https://widget.mride.com/api/v1 |
Base URL for the ETA API. |
data-stylesheet |
No | Hosted CDN URL | URL to the widget's main CSS file. |
data-fonts |
No | Hosted CDN URL | URL to the widget's fonts CSS file. |
data-brand |
No | Hosted CDN URL | URL to a brand/theme CSS file for visual customization. |
data-program |
No | mride |
Default partner program applied to all buttons. Can be overridden per button. |
data-strip-return-params |
No | false |
When true, strips query parameters from the return URL after Stripe checkout completes. |
data-on-error |
No | — | Name of a global JavaScript function to call when an unhandled error occurs. See Error Handling. |
data-on-order-begin |
No | — | Name of a global JavaScript function to call when a customer begins an order. |
data-on-order-complete |
No | — | Name of a global JavaScript function to call when an order is completed. |
2. Add Event Buttons
Place one or more buttons anywhere in your page. Each button must have the CSS class that matches data-trigger-class on the script tag (default: shuttle-btn).
<button class="shuttle-btn" data-event-id="your-event-id">
Book Now
</button>
Button Attributes
| Attribute | Required | Description |
|---|---|---|
data-event-id |
Yes | The event identifier to load when this button is clicked. |
data-promo-code |
No | A promo/discount code to apply automatically when the widget opens. |
data-program |
No | Partner program for this button. Overrides the script-level data-program value. |
3. Examples
Single event, no customization
<button class="shuttle-btn" data-event-id="my-event">Book Now</button>
<script id="eta-buy-button"
src="https://widget.mride.com/static/js/widget.js"
type="module"
data-api-url="https://widget.mride.com/api/v1">
</script>
Multiple events on the same page
All buttons sharing data-trigger-class are handled by a single widget instance.
<button class="shuttle-btn" data-event-id="ed-sheeran-sf-26">Book Ed Sheeran Shuttle</button>
<button class="shuttle-btn" data-event-id="foo-fighters-lv-26">Book Foo Fighters Shuttle</button>
<script id="eta-buy-button"
src="https://widget.mride.com/static/js/widget.js"
type="module"
data-api-url="https://widget.mride.com/api/v1">
</script>
Pre-apply a promo code
The widget will automatically apply the discount when the modal opens.
<button class="shuttle-btn"
data-event-id="summer-festival"
data-promo-code="SUMMER20">
Book with Discount
</button>
Partner program
M Ride can create a program for your organization. A program enables the following capabilities, configured by M Ride on your behalf:
- Custom branded confirmation emails — full branding and content, sent from your email address, with optional BCC recipients
- Automatic discounts — pre-applied discount rates reflecting agreed-upon partner pricing, with no promo code required from the customer
- Filtered pickup locations — only the pickup locations relevant to your program are shown in the widget; all others are excluded from every API response
Contact your M Ride representative to have a program created. Once set up, you reference it by its program identifier in your button or script tag configuration.
Override the default program on a per-button basis.
<!-- Uses the default program from the script tag -->
<button class="shuttle-btn" data-event-id="my-event">Book Now</button>
<!-- Uses a specific partner program for this button -->
<button class="shuttle-btn"
data-event-id="edc-lv-26"
data-program="hotel-partner-name">
Book (Hotel Guests)
</button>
To apply a partner program globally to all buttons, set it on the script tag instead:
<script id="eta-buy-button"
src="https://widget.mride.com/static/js/widget.js"
type="module"
data-program="hotel-partner-name"
data-api-url="https://widget.mride.com/api/v1">
</script>
Custom stylesheet / branding
<script id="eta-buy-button"
src="https://widget.mride.com/static/js/widget.js"
type="module"
data-stylesheet="https://yoursite.com/css/widget.css"
data-fonts="https://yoursite.com/css/fonts.css"
data-brand="https://yoursite.com/css/brand.css"
data-api-url="https://widget.mride.com/api/v1">
</script>
4. URL-Based Promo Codes
In addition to the data-promo-code button attribute, the widget also reads promo codes from the page URL. If the URL contains a ?promo=CODE query parameter, it is automatically applied when any button is clicked. The URL parameter takes precedence over the button attribute.
5. Error Handling
Set data-on-error to the name of a global function. The function receives an object with the eventId that triggered the error. Return true to suppress the widget's default error message.
<script id="eta-buy-button"
src="https://widget.mride.com/static/js/widget.js"
type="module"
data-on-error="handleWidgetError"
data-api-url="https://widget.mride.com/api/v1">
</script>
<script>
function handleWidgetError(error) {
console.error("Widget error for event:", error.eventId);
// Return true to suppress the default "Something went wrong" message
return true;
}
</script>
HTTP error codes the widget handles automatically:
| Status | Message shown |
|---|---|
404 |
"We could not find this event" |
410 |
"Sales have ended for this event" |
| Other | "Something went wrong" (calls data-on-error if set) |
6. Security & Compliance
Domain Whitelisting
The M Ride API enforces CORS (Cross-Origin Resource Sharing), which means the widget will only function on domains that have been explicitly authorized. Before going live, contact your M Ride representative to have your domain added to the allowlist. Requests from non-whitelisted domains will be blocked by the browser before they reach the API.
Payment Data & PCI Compliance
The widget itself does not collect, handle, or store any payment card data. All payment information is entered directly into and processed by Stripe, a PCI-DSS Level 1 certified payment processor. Card numbers, expiry dates, and CVVs never pass through your website or M Ride's servers. This architecture keeps your site out of PCI scope for cardholder data.
Customer Data Collection
The widget does not collect customer personal data (name, email, phone, etc.) at any point during the booking flow. Customer information is collected by Stripe during checkout.
After a payment clears, Stripe notifies the M Ride API via a signed webhook. The following data is then received and stored by M Ride's servers:
- First name, last name
- Email address
- Phone number
- Order line items (shuttles, dates, quantities)
No customer data is transmitted through the JavaScript widget or your web page.
Webhook Security
The Stripe webhook sent to the M Ride API is cryptographically signed by Stripe. M Ride's API verifies this signature on every webhook delivery, ensuring that order data cannot be fabricated or tampered with by a third party.
What Your Site Is Responsible For
| Concern | Handled by |
|---|---|
| Payment card data security | Stripe (PCI-DSS Level 1) |
| Webhook integrity | Stripe signature + M Ride API |
| Customer PII storage | M Ride API (post-payment only) |
| Widget JS & CSS delivery | M Ride CDN (or your own hosting) |
| Domain authorization | M Ride (contact your representative) |
| Your page's own security (HTTPS, CSP, etc.) | You |
Ensure your page is served over HTTPS. Loading the widget on an unencrypted HTTP page will cause browsers to block the Stripe checkout iframe.
7. Testing
M Ride provides a test environment that runs against Stripe's test mode. Orders placed in test mode do not consume production inventory and no real charges are made.
Enabling Test Mode
Set data-api-url to the test API endpoint:
<script id="eta-buy-button"
src="https://widget.mride.com/static/js/widget.js"
type="module"
data-api-url="https://widget-test.mride.com/api/v1">
</script>
| Environment | data-api-url |
|---|---|
| Production | https://widget.mride.com/api/v1 |
| Test | https://widget-test.mride.com/api/v1 |
The widget script src is the same for both environments.
Note: Your domain must be whitelisted in the test environment separately from production. Contact your M Ride representative to have it added.
Test Credit Card Numbers
Use these Stripe-provided card numbers at checkout. Enter any future expiry date (e.g. 12/34), any 3-digit CVC, and any billing ZIP code.
| Card number | Brand | Behavior |
|---|---|---|
4242 4242 4242 4242 |
Visa | Payment succeeds |
5555 5555 5555 4444 |
Mastercard | Payment succeeds |
4000 0025 0000 3155 |
Visa | Requires 3D Secure authentication |
4000 0000 0000 9995 |
Visa | Declined — insufficient funds |
4000 0000 0000 0002 |
Visa | Declined — generic decline |
A successful test order will complete the full flow: payment confirmation, webhook delivery, and the download screen with QR codes.
8. Notes
- Only one widget instance is created per page, regardless of how many buttons are present.
- The widget renders inside a Shadow DOM, so your page's existing CSS will not interfere with its styles.
- The widget automatically positions itself above all other elements on the page by computing the highest
z-indexat load time.
