Skip to main content

How to let Admin members add and tag new users from a Webflow dashboard in MS?

Hi, Im kinda new to memberstack and have connected it to my webflow site. I have setup two diffrent free plans, one education and one Admin. I want the ones with Admin to be able to add new user to education and give them diffrent tags (groups) but all in a dashboard like interface on my webflow site. is this possible and if so how?

14 comments

  • A J
    A J

    Hey Adam olin,

    If you don't want to add them as admins in Memberstack dashboard and instead want to create a dashboard like interface, you can custom build it as per your requirements.

    For example you could have a form on the webflow site which takes the student's email, plan to be assigned etc. as details and this form can be connected to an automation workflow via Make / Zapier which will create a new member in Memberstack and assign them the free plans accordingly.

    Then those students can possibly login via Passwordless method and then have an option to set password further down the line if they want etc.

    So yes, this should be possible, you might need to explore and customize things a bit based on the design requirements as well.

    Hope this gives you some idea.

    0
  • Adam olin
    Adam olin OP

    Thanks for the respons, this helped and I have now manage to make it so those with admin free plan can add members from the site and they get education plan automaticlly. The problem now is that I have this table on the admin site that display the data table I have setup in memberstack but I cant get the automation that all members that get the education plan to get added to the table. and tips for that part?

    0
  • A J
    A J

    Welcome Adam olin 😇

    You can setup a custom script on the page where the admin adds member and the script can add a new record to the data table in Memberstack accordingly. You can take inspiration from this memberscript and customize it for your use-case and then push the data to the webhook that goes on to add the member in Memberstack and assign them the relevant plan etc.

    Hope this helps.

    0
  • Adam olin
    Adam olin OP

    Hi again, I dont really get it to work. is it possible to insted of displaying the data table display the pepole with a surtain plan. so for me its everyone with education plan assiged to them

    0
  • A J
    A J

    Hey Adam olin,

    While Memberstack dashboard has all the data of members and plans they are assigned, when it comes to showing it on the front-end in Webflow, it becomes tricky as one logged in user does not have access to other users' personal data by default.

    So, the workaround becomes to store the relevant information in a database like Data Tables / Webflow CMS (but it might have limitations when the business scales to huge scale of members). So storing and displaying via Data Tables should work for your use-case as you have control over what information is shared with the admin user (since you don't want them to have full access to Memberstack dashboard) and it would be easier to maintain from your end as well.

    Are you facing any blockers in implementing this? Feel free to share the sandbox link and explain a bit more about the blocker if any, so that I can probably help in troubleshooting.

    0
  • Adam olin
    Adam olin OP
    Ahh I see, here is the sandbox link https://preview.webflow.com/preview/anturas-kundportal?utm_medium=preview_link&utm_sou[…]&pageId=69830a8ae0c9406ca9de0116&locale=en&workflow=preview

    the admin page it hidden behind plan based block now. only those that have a plan called admin can see it, Not sure if its possible to view in sandbox mode or not
    0
  • A J
    A J

    Okay can you explain what blocker you are facing currently?

    0
  • Adam olin
    Adam olin OP

    when I submit a new user in any of the forms im testing it dosnt get added to the data table I have set up in memberstack, the first unstyled table is also connected to a make automation where the data enterd makes a new education member in memberstack witch works fine. The secoond one that is a code block is something memberstack AI made that dosnt work at all. And the last one that looks like the one like in the video you sent earlier is just a clone of that one where I change the table name and the field to match the ones on my table

    0
  • A J
    A J

    Adam olin, does the make automation listen to webflow form submissions and goes ahead with the member creation and plan assignment? i.e. is the first module in that automation a Webflow module?

    0
  • Adam olin
    Adam olin OP

    Yes it looks like this, I do get some error every now and then and might swap ti zapier, I have used it alot more before.

    0
  • A J
    A J

    Hey Adam olin,

    You can probably create a custom webhook in Make / Zapier (instead of using the Webflow form submission module) and link it to the form in Webflow, via the form settings (as highlighted in the screenshot below). After clicking custom action, you can paste the webhook URL from Make / Zapier to the Action field and save it.

    I have modified the memberscript I shared earlier to specifically work for your use-case as follows:

    <script> document.addEventListener("DOMContentLoaded", function() {   const forms = document.querySelectorAll('[data-ms-code="form1"]');      // Helper function to show loading state   function setLoadingState(form, isLoading) {     const submitButton = form.querySelector('button[type="submit"], input[type="submit"], button:not([type])');     const originalButtonText = submitButton ? submitButton.textContent || submitButton.value : '';          if (submitButton) {       submitButton.disabled = isLoading;       submitButton.style.opacity = isLoading ? '0.6' : '1';       submitButton.style.cursor = isLoading ? 'not-allowed' : 'pointer';              if (isLoading) {         submitButton.dataset.originalText = originalButtonText;         submitButton.textContent = 'Saving...';         if (submitButton.value) submitButton.value = 'Saving...';       } else {         const original = submitButton.dataset.originalText || originalButtonText;         submitButton.textContent = original;         if (submitButton.value) submitButton.value = original;         delete submitButton.dataset.originalText;       }     }          // Disable all inputs during save     const inputs = form.querySelectorAll('input, textarea, select, button');     inputs.forEach(input => {       if (input !== submitButton) {         input.disabled = isLoading;       }     });   }      // Helper function to show success message   function showSuccessMessage(form, message) {     // Remove any existing messages     const existingMessage = form.querySelector('[data-ms-code="success-message"]');     if (existingMessage) existingMessage.remove();          // Create success message element     const successMsg = document.createElement('div');     successMsg.setAttribute('data-ms-code', 'success-message');     successMsg.textContent = message || 'Saved successfully!';     successMsg.style.cssText = 'padding: 12px; background-color: #10b981; color: white; border-radius: 6px; margin-top: 12px; font-size: 14px; text-align: center; animation: fadeIn 0.3s ease-in;';          // Add fade-in animation if not exists     if (!document.getElementById('ms198-styles')) {       const style = document.createElement('style');       style.id = 'ms198-styles';       style.textContent = `         @keyframes fadeIn {           from { opacity: 0; transform: translateY(-10px); }           to { opacity: 1; transform: translateY(0); }         }         @keyframes fadeOut {           from { opacity: 1; }           to { opacity: 0; }         }       `;       document.head.appendChild(style);     }          form.appendChild(successMsg);          // Remove message after 3 seconds     setTimeout(() => {       successMsg.style.animation = 'fadeOut 0.3s ease-out';       setTimeout(() => successMsg.remove(), 300);     }, 3000);   }      // Helper function to show error message   function showErrorMessage(form, message) {     const existingMessage = form.querySelector('[data-ms-code="error-message"]');     if (existingMessage) existingMessage.remove();          const errorMsg = document.createElement('div');     errorMsg.setAttribute('data-ms-code', 'error-message');     errorMsg.textContent = message || 'Failed to save. Please try again.';     errorMsg.style.cssText = 'padding: 12px; background-color: #ef4444; color: white; border-radius: 6px; margin-top: 12px; font-size: 14px; text-align: center; animation: fadeIn 0.3s ease-in;';          form.appendChild(errorMsg);          setTimeout(() => {       errorMsg.style.animation = 'fadeOut 0.3s ease-out';       setTimeout(() => errorMsg.remove(), 5000);     }, 5000);   }      forms.forEach(form => {     const dataType = form.getAttribute("data-ms-code-table-type");     const tableName = form.getAttribute("data-ms-code-table");     const memberField = form.getAttribute("data-ms-code-member-field") || 'member';     const storageKey = form.getAttribute("data-ms-code-storage-key") || "memberDataTable";     const webhookUrl = form.getAttribute('action');     // Disable Webflow form submission     form.setAttribute('action', 'javascript:void(0);');     form.setAttribute('method', 'post');     form.setAttribute('novalidate', 'novalidate');          // Prevent any Webflow form handlers     form.addEventListener('submit', function(e) {       e.preventDefault();       e.stopPropagation();       return false;     }, { capture: true, passive: false });     form.addEventListener('submit', async function(event) {       event.preventDefault(); // Prevent the default form submission       event.stopPropagation(); // Stop event bubbling       event.stopImmediatePropagation(); // Stop other handlers              const formData = new FormData(form);       // Set loading state       setLoadingState(form, true);              // Remove any existing messages       const existingMessages = form.querySelectorAll('[data-ms-code="success-message"], [data-ms-code="error-message"]');       existingMessages.forEach(msg => msg.remove());       // Get Memberstack instance       const memberstack = window.$memberstackDom;       if (!memberstack) {         setLoadingState(form, false);         showErrorMessage(form, 'Memberstack not initialized');         return;       }       // Validate required attributes       if (!tableName) {         setLoadingState(form, false);         showErrorMessage(form, 'Table name required. Add data-ms-code-table attribute to form.');         return;       }       // Get current member       const memberResult = await memberstack.getCurrentMember();       const member = memberResult?.data || memberResult;       if (!member?.id) {         setLoadingState(form, false);         showErrorMessage(form, 'Please log in to save data');         return;       }       if (dataType === "group") {         // Create a single record with multiple fields (group of key-value pairs)         const inputs = form.querySelectorAll('[data-ms-code-table-name]');         const recordData = {           [memberField]: member.id // Link record to member         };         inputs.forEach(input => {           const fieldName = input.getAttribute('data-ms-code-table-name');           const fieldValue = input.value;           if (fieldName) {             recordData[fieldName] = fieldValue || null;           }         });         try {           await memberstack.createDataRecord({             table: tableName,             data: recordData           });                     setLoadingState(form, false);           showSuccessMessage(form, 'Saved successfully!');           // Trigger #199 to sync localStorage immediately           if (window.ms199SyncDataTable) {             window.ms199SyncDataTable();           }           // Trigger #200 to update latest record in localStorage (with small delay to ensure save)           if (window.ms200UpdateLocalStorage) {             window.ms200UpdateLocalStorage(tableName, storageKey, 500);           }         } catch (error) {           // Try with member as object if direct ID fails           try {             const retryData = { ...recordData };             retryData[memberField] = { id: member.id };             await memberstack.createDataRecord({               table: tableName,               data: retryData             });             setLoadingState(form, false);             showSuccessMessage(form, 'Saved successfully!');             // Trigger #199 to sync localStorage immediately             if (window.ms199SyncDataTable) {               window.ms199SyncDataTable();             }             // Trigger #200 to update latest record in localStorage (with small delay to ensure save)             if (window.ms200UpdateLocalStorage) {               window.ms200UpdateLocalStorage(tableName, storageKey, 500);             }           } catch (retryError) {             setLoadingState(form, false);             showErrorMessage(form, 'Failed to save. Please try again.');           }         }         if (webhookUrl && webhookUrl !== 'javascript:void(0);') {           try {             await fetch(webhookUrl, {               method: 'POST',               body: formData             });           } catch (webhookErr) {             console.error('Webhook Failed:', webhookErr);           }         }       }             // Reset the input values       const inputs = form.querySelectorAll('[data-ms-code-table-name]');       inputs.forEach(input => {         input.value = "";       });              return false; // Prevent any further form submission     }, { capture: true });   }); }); </script> 

    So you can replace the custom code in 'Before </body> tag' section in the Admin page with the above script.

    This will work with the 'Save an item with properties (Group)' form that came with the memberscript cloneable I shared.

    After ensuring the form's 'Send To' is linked to a custom action (i.e. your webhook) and publishing the site with the modified script, the data submitted by the admin should be pushed to the relevant data table as well as the automation workflow via which you will create the member and assign them plan etc.

    I have personally tested this out to see if it works and it does on my end.

    You can test it out on your end to see if it works for your project.

    Hope this helps

    0
  • Adam olin
    Adam olin OP
    Hi sorry for the late reply, I have tested it now aswell and something isnt working.When I click "save item" now I get ported to the webhook URL and it says "Unauthorized." I created the custumwebhook in Make and liked it as a custum action. something that I missed? I have also copied your code in the body of the page
    0
  • A J
    A J

    Hey Adam olin,

    Make sure while creating a webhook in Make scenario, you leave the highlighted part in the screenshot as it is and only set the webhook's name and save it.

    Then test the site out and ideally it should work.

    Hope this helps

    0
  • Adam olin
    Adam olin OP

    I got it working now! thanks for the help 😄

    0

Please sign in to leave a comment.

Sitemap