Have something to say?

Tell us how we could make the product more useful to you.

Control the number of devices where the subscription is used

The pain is to monetize those who buy 1 subscription for 5+ devices (which fits the Enterprice description and should be billed differently) As far as I understand some kind of fingerprinting is already built into peivol, so we can break the task down into subtasks: 1) to start with it would be cool to be able to see on how many devices the subscriber has activated the app on 2) The next step would be logical to give functionality to limit the number of uses for certain plans. That will allow to create a separate ala Enterprise plan for the number of users. P.S Perhaps this task is somehow related to the task about discount coupons, because in fact it introduces additional customization of the flat payment system.

DreamBuilder Team About 1 month ago

Поддержать нативный российский пэйволл без модерации

Например Robokassa поддерживает оплату с западных карт - https://robokassa.com/payments/payment-method/inostrannye-karty/ , кажется слышал и о других подобных сервисах. Не очень важно какой именно поддерживать - лишь бы вы могли смело использовать боевую версию. Какую проблему решает: позволяет проще экспериментировать. Будет дорого и наверное часть клиентов отвалятся не увидев знакомого stripe, но можно хоть каждый месяц пробовать на новом продукте без необходимости рассмотрения и одобрения monetize software (а часто же собственно готовность пользователей оплатить и подтверждает полезность проекта). А если хоть какие-то оплаты пойдут, тогда уже переходить с беседам о поддержке основных payment providers через monetize software. P.S. Годятся даже сильные ограничения, например, не больше N подписок на M долларов через robokassa. Речь не о том, чтобы “на самом деле” пользоваться робокассой - у них и цены негуманные, и они не совсем про построение комьюнити разработчиков. Цель в снижении барьера для “попробовать оплатит ли хоть кто-то хоть что-нибудь” и желательно так, чтобы переезд на правильное решение в дальнейшем был бы не сложен.

Artem Marchenko 3 months ago

1

Add TypeScript Example to Install Script Instructions

Hey team. It would be great to include a TypeScript implementation in the install/setup script examples of background.js. Right now, the docs only show a plain JavaScript version, which causes TypeScript to complain about missing types or implicit anys. Since most projects today use TS by default, having a TypeScript-friendly snippet (with proper typings) would make onboarding much smoother. Here’s an example of a version with typings: // use same paywall id everywhere export const PAYWALL_ID = XXX; const connectedPorts = new Set (); chrome.runtime.onConnectExternal.addListener(port => { if ( port.sender?.url && (port.sender.url.includes('onlineapp.pro') || port.sender.url.includes('onlineapp.live') || port.sender.url.includes('onlineapp.stream')) ) { connectedPorts.add(port); port.onDisconnect.addListener(() => { connectedPorts.delete(port); }); } else { console.warn('Connection attempt from unauthorized domain:', port.sender?.url); port.disconnect(); } }); function trackEvent(eventName: string, additionalData = {}) { getUserId((userId: string) => { fetch('https://onlineapp.pro/api/track-event', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ event: eventName, wallId: PAYWALL_ID, extensionId: chrome.runtime.id, userId: userId, ...additionalData, }), }); }); } function notifyConnectedClients(notification: Record) { connectedPorts.forEach(port => { try { port.postMessage(notification); } catch (error) { console.error('Error sending notification to port:', error); connectedPorts.delete(port); } }); } function getUserId(callback: (user_id: string) => void) { chrome.storage.sync.get(['user_id'], result => { if (result.user_id) { callback(result.user_id); } else { const userId = crypto.randomUUID(); chrome.storage.sync.set({ user_id: userId, ['pw-591-visitor-id']: userId }, () => { callback(userId); }); } }); } chrome.runtime.onMessageExternal.addListener((message, sender, sendResponse) => { if ( sender.url && (sender.url.includes('onlineapp.pro') || sender.url.includes('onlineapp.live') || sender.url.includes('onlineapp.stream')) ) { if (message.source === 'supabase-auth-adapter') { switch (message.action) { case 'ping': sendResponse({ status: 'ok' }); break; case 'getItem': try { const { key } = message.data; chrome.storage.sync.get(key, result => { if (chrome.runtime.lastError) { const errorMessage = chrome.runtime.lastError.message; console.error('Storage error:', errorMessage); sendResponse({ status: 'error', message: errorMessage }); } else { sendResponse({ status: 'success', value: result[key] || null }); } }); return true; } catch (error) { if (error instanceof Error) { console.error('Error in getItem:', error); sendResponse({ status: 'error', message: error.message }); } } break; case 'setItem': try { const { key, value } = message.data; chrome.storage.sync.set({ [key]: value }, () => { if (chrome.runtime.lastError) { const errorMessage = chrome.runtime.lastError.message; console.error('Storage error:', errorMessage); sendResponse({ status: 'error', message: errorMessage }); } else { sendResponse({ status: 'success' }); notifyConnectedClients({ type: 'storage_update', action: 'set', key, value, timestamp: Date.now(), }); } }); return true; } catch (error) { if (error instanceof Error) { console.error('Error in setItem:', error); sendResponse({ status: 'error', message: error.message }); } } break; case 'removeItem': try { const { key } = message.data; chrome.storage.sync.remove(key, () => { if (chrome.runtime.lastError) { const errorMessage = chrome.runtime.lastError.message; console.error('Storage error:', errorMessage); sendResponse({ status: 'error', message: errorMessage }); } else { notifyConnectedClients({ type: 'storage_update', action: 'remove', key, timestamp: Date.now(), }); sendResponse({ status: 'success' }); } }); return true; } catch (error) { if (error instanceof Error) { console.error('Error in removeItem:', error); sendResponse({ status: 'error', message: error.message }); } } break; default: console.warn('Unknown action:', message.action); sendResponse({ status: 'error', message: 'Unknown action' }); break; } } else if (message.type === 'broadcast') { notifyConnectedClients(message.data || message); sendResponse({ status: 'success', message: 'Message broadcasted successfully', clientsCount: connectedPorts.size, }); } else { console.warn('Message has neither source nor type'); sendResponse({ status: 'error', message: 'Invalid message format' }); } } else { console.warn('Message from unauthorized domain:', sender.url); sendResponse({ status: 'error', message: 'Unauthorized domain' }); } return true; });

Alexander Kozhurkin 3 months ago

Часто на вкалдке Users и subscriptions показываает разные страны

Часто на вкалдке Users и subscriptions показываает разные страны Кто-то говорил что там есть разница по определению стран на разных этапах (IP или карта оплаты) - если так, то надо как-то это в UI разделить чтобы было поянтно почему так. Пример monetize.software/ru/publisher/overview Step 1: Navigate to: monetize.software/ru/publisher/overview Step 2: Select area on page Step 3: Navigate to: https://monetize.software/ru/publisher/overview?tab=subscriptions Step 4: Select area on page Created using Step by step instructions: Guide To Docs 1.3.0.1

DreamBuilder Team 4 months ago

Completed

Whitelist Users by Email to Bypass Paywall Display

Add the ability to whitelist users by their email addresses, allowing them to bypass the paywall. This feature is essential for granting direct access to specific individuals, such as corporate clients or manually approved users, without requiring them to interact with the standard payment flow. Frontend Requirements: Implement a UI component on the paywall page to manage a whitelist. The component should display a list of email addresses. Allow adding and removing email entries from this list. Backend Requirements: Store and manage the whitelist on the backend. When paywall.open() is triggered, skip displaying the paywall for users whose email is on the whitelist. This functionality ensures a smoother experience for special access cases, such as direct corporate agreements or promotional access.

Andrey Volkov 7 months ago

1