diff --git a/BTCPayServer/wwwroot/shopify/btcpay-browser-client.js b/BTCPayServer/wwwroot/shopify/btcpay-browser-client.js
new file mode 100644
index 000000000..d73aa9804
--- /dev/null
+++ b/BTCPayServer/wwwroot/shopify/btcpay-browser-client.js
@@ -0,0 +1,88 @@
+/* Based on @djseeds script: https://github.com/btcpayserver/btcpayserver/issues/36#issuecomment-633109155 */
+/*** Creates a new BTCPayServer Modal
+ * @param url - BTCPayServer Base URL
+ * @param storeId - BTCPayServer store ID
+ * @param data - Data to use for invoice creation
+* @returns - A promise that resolves when invoice is paid.
+* ***/
+var BtcPayServerModal = (function () {
+ function waitForPayment(btcPayServerUrl, invoiceId, storeId) {
+ // Todo: mutex lock on btcpayserver modal.
+ return new Promise(function (resolve, reject) {
+ // Don't allow two modals at once.
+ if (waitForPayment.lock) {
+ resolve(null);
+ }
+ else {
+ waitForPayment.lock = true;
+ }
+ window.btcpay.onModalWillEnter(function () {
+ var interval = setInterval(function () {
+ getBtcPayInvoice(btcPayServerUrl, invoiceId, storeId)
+ .then(function (invoice) {
+ if (invoice.status == "complete") {
+ clearInterval(interval);
+ resolve(invoice);
+ }
+ })
+ .catch(function (err) {
+ clearInterval(interval);
+ reject(err);
+ });
+ }, 1000);
+ window.btcpay.onModalWillLeave(function () {
+ waitForPayment.lock = false;
+ clearInterval(interval);
+ // If user exited the payment modal,
+ // indicate that there was no error but invoice did not complete.
+ resolve(null);
+ });
+ });
+ window.btcpay.showInvoice(invoiceId);
+ });
+ }
+
+ function getBtcPayInvoice(btcPayServerUrl, invoiceId, storeId) {
+ const url = btcPayServerUrl + "/invoices/" + invoiceId + "?storeId=" + storeId;
+ return fetch(url, {
+ method: "GET",
+ mode: "cors", // no-cors, cors, *same-origin,
+ headers: {
+ "Content-Type": "application/json",
+ "accept": "application/json",
+ }
+ })
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (json) {
+ return json.data;
+ })
+ }
+
+ return {
+ show: function (url, storeId, data) {
+ const path = url + "/invoices?storeId=" + storeId;
+ return fetch(path,
+ {
+ method: "POST",
+ mode: "cors",
+ headers: {
+ "Content-Type": "application/json",
+ "accept": "application/json",
+ },
+ body: JSON.stringify(data)
+ }
+ )
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (response) {
+ return waitForPayment(url, response.data.id, storeId);
+ });
+ },
+ hide: function () {
+ window.btcpay.hideFrame();
+ }
+ }
+})()
diff --git a/BTCPayServer/wwwroot/shopify/btcpay-shopify-checkout.js b/BTCPayServer/wwwroot/shopify/btcpay-shopify-checkout.js
new file mode 100644
index 000000000..c736b9315
--- /dev/null
+++ b/BTCPayServer/wwwroot/shopify/btcpay-shopify-checkout.js
@@ -0,0 +1,138 @@
+/* Based on @djseeds script: https://github.com/btcpayserver/btcpayserver/issues/36#issuecomment-633109155 */
+
+/*
+
+1. In your BTCPayServer store you need to check "Allow anyone to create invoice"
+2. In Shopify Settings > Payment Providers > Manual Payment Methods add one which contains "Bitcoin"
+3. In Shopify Settings > Checkout > Additional Scripts input the following script, with the details from your BTCPayServer instead of the placeholder values.
+
+
+
+
+
+ */
+
+! function () {
+ "use strict";
+ const pageElements = document.querySelector.bind(document),
+ insertElement = (document.querySelectorAll.bind(document),
+ (e,
+ n) => {
+ n.parentNode.insertBefore(e,
+ n.nextSibling)
+ });
+
+ let pageItems = {},
+ pageheader = "Thank you!",
+ buttonElement = null;
+
+ const setPageItems = () => {
+ pageItems = {
+ mainHeader: pageElements("#main-header"),
+ orderConfirmed: pageElements(".os-step__title"),
+ orderConfirmedDescription: pageElements(".os-step__description"),
+ continueButton: pageElements(".step__footer__continue-btn"),
+ checkMarkIcon: pageElements(".os-header__hanging-icon"),
+ orderStatus: pageElements(".os-header__title"),
+ paymentMethod: pageElements(".payment-method-list__item__info"),
+ price: pageElements(".payment-due__price"),
+ finalPrice: pageElements(".total-recap__final-price"),
+ orderNumber: pageElements(".os-order-number"),
+ }
+ }
+
+ const orderPaid = () => {
+ pageItems.mainHeader.innerText = pageheader,
+ pageItems.orderConfirmed && (pageItems.orderConfirmed.style.display = "block"),
+ pageItems.orderConfirmedDescription && (pageItems.orderConfirmedDescription.style.display = "block"),
+ pageItems.continueButton && (pageItems.continueButton.style.visibility = "visible"),
+ pageItems.checkMarkIcon && (pageItems.checkMarkIcon.style.visibility = "visible"),
+ buttonElement && (buttonElement.style.display = "none");
+ };
+
+ window.setOrderAsPaid = orderPaid,
+ window.openBtcPayShopify = function waitForPaymentMethod() {
+ if (setPageItems(), "Order canceled" === pageItems.orderStatus.innerText) {
+ return;
+ }
+
+ const paymentMethod = pageItems.paymentMethod;
+
+ if (null === paymentMethod) {
+ return void setTimeout(() => {
+ waitForPaymentMethod();
+ }, 10);
+ }
+
+ if (-1 === paymentMethod.innerText.toLowerCase().indexOf("bitcoin")) return;
+
+ // If payment method is bitcoin, display instructions and payment button.
+ pageheader = pageItems.mainHeader.innerText,
+ pageItems.mainHeader && (pageItems.mainHeader.innerText = "Review and pay!"),
+ pageItems.continueButton && (pageItems.continueButton.style.visibility = "hidden"),
+ pageItems.checkMarkIcon && (pageItems.checkMarkIcon.style.visibility = "hidden"),
+ pageItems.orderConfirmed && (pageItems.orderConfirmed.style.display = "none"),
+ pageItems.orderConfirmedDescription && (pageItems.orderConfirmedDescription.style.display = "none"),
+ buttonElement = document.createElement("div");
+
+ const priceElement = pageItems.finalPrice || pageItems.price;
+ var price = priceElement.innerText.replace(DEFAULT_CURRENCY_SYMBOL, "").replace(THOUSAND_DELIMITER, "");
+ if (THOUSAND_DELIMITER === ".") {
+ price = price.replace(",", "."); // 5.000,00 needs to become 5000.00
+ }
+ const orderId = pageItems.orderNumber.innerText.replace("Order #", "");
+
+ const url = BTCPAYSERVER_URL + "/invoices" + "?storeId=" + STORE_ID + "&orderId=" + orderId + "&status=complete";
+
+ // Check if already paid.
+ fetch(url, {
+ method: "GET",
+ mode: "cors", // no-cors, cors, *same-origin,
+ headers: {
+ "Content-Type": "application/json",
+ "accept": "application/json",
+ },
+ })
+ .then(function (response) {
+ return response.json();
+ })
+ .then(function (json) {
+ return json.data;
+ })
+ .then(function (data) {
+ if (data.length != 0) {
+ orderPaid();
+ }
+ });
+
+ window.waitForPayment = function () {
+ BtcPayServerModal.show(
+ BTCPAYSERVER_URL,
+ STORE_ID,
+ {
+ price: price,
+ currency: DEFAULT_CURRENCY,
+ orderId: orderId
+ }
+ )
+ .then(function (invoice) {
+ if (invoice != null) {
+ orderPaid();
+ }
+ });
+ }
+
+ // Payment button that opens modal
+ buttonElement.innerHTML = `\n Pay with BTCPayServer\n`,
+ insertElement(buttonElement, pageItems.orderConfirmed);
+
+ }
+
+ window.openBtcPayShopify();
+}();