REX: Building a SaaS from Wagtail

This video is from Wagtail Space 2025 in Online.

REX: Building a SaaS from Wagtail
0:27:47
Published November 19, 2025
72 views

In 2023, RGOODS decided to launch its online donation form service for NGOs and associations. In order to accelerate development and avoid reinventing the wheel, we decided to rely on Django and Wagtail.

This talk will present how we twisted Wagtail to use it as a SaaS platform, using examples and outlining what makes Wagtail an interesting foundation for building a SaaS business application, outside of its core CMS business, and how our users benefit from its ‘killer features’.

We will also discuss how we contribute back to the project and we follow Wagtail development.

💻 Wagtail is the easiest open-source Python CMS to use:
Install the demo and start building your first site in 10 minutes: https://wagtail.org/get-started/

📹 Related Videos To Watch Next:

â–¶ Quick Video Tour of Wagtail CMS 7.0 https://youtu.be/r5RbV7TveFU
â–¶ The Latest on Wagtail AI https://www.youtube.com/watch?v=4zfs1u4Vy5Y
▶ What’s New in Wagtail CMS 7.0 https://youtu.be/v92-6Dy4axI

Wagtail future proofs your CMS system, as it’s open source, continuously updated and built on Python, one of the most popular global programming languages, used widely in machine learning and big data. So you’re always ahead of the curve when it comes to CMS platforms.

Wagtail is the #1 choice for accessibility, is scalable and most importantly, secure.

👉 Get started with Wagtail CMS for free: https://wagtail.org/get-started/
and see how easy it is to build a website that works for you.

📊 Read why Google, NASA, and the British NHS, are powering their digital estates with Wagtail: https://wagtail.org/about-wagtail/

🎥 More Wagtail Videos: https://www.youtube.com/watch?v=cne2kxemMAQ&list=PLfwZ-fob20cPvSQ_v1hkjto8BAPN21tLJ

📣 Follow us on social:

#WagtailCMS #Django

Summary

Sebastian Corbin explains how AirGoods built AirGive, a SaaS donation-form platform for medium and large European NGOs, on Django and Wagtail. Wagtail provides the editorial and administrative foundations, while custom use of StreamField, snippets, universal listings, audit logs, preview modes, routable pages, and Wagtail’s UI components supports configurable campaigns, exports, branding, and donor-facing experiences. The platform isolates each client with a separate database schema and workers, protects the back office behind VPN access, and uses a payment orchestrator to handle multiple providers. Corbin argues that staying close to Wagtail core and contributing fixes upstream is more practical than maintaining a fork, and describes the technical trade-offs involved in translations, multi-tenancy, infrastructure, and client onboarding.

Key takeaways

  • AirGive targets medium and large European NGOs that need GDPR-aware donation forms, tailored branding, flexible payment methods, and CRM-ready exports.
  • Wagtail’s StreamField is used not only for editorial content but also for structured configuration such as export formats, payment data transformers, and dynamic templates.
  • Universal listings, model viewsets, audit logs, generic settings, preview modes, and Wagtail UI components reduce the amount of custom administration code required.
  • AirGoods separates front-end and back-office deployments, protects administration behind VPN access, and runs dedicated workers for each client.
  • Each client currently has a separate database schema to prevent data leakage, while Django Localized Fields supports languages that clients can activate without new deployments.
  • The team avoids forking Wagtail, keeps current with core releases, and contributes features and fixes back to the project.

Summarised automatically from the transcript.

Chapters

  1. 0:00 AirGoods and AirGive Sebastian introduces AirGoods, its nonprofit-focused products, and the AirGive donation platform.
  2. 2:42 AirGive Product Strategy The talk covers AirGive’s fundraising features, donor experience, customization, data exports, and payment configuration.
  3. 5:51 The Case for Wagtail Sebastian explains the European market, the needs of medium and large NGOs, and why the team chose Wagtail with Django.
  4. 8:10 Administrative Features The presentation examines model administration, universal listings, audit logs, generic settings, previews, and branded interfaces.
  5. 12:00 Configurable Content and Exports StreamField is used for semi-structured configuration, flexible export formats, campaign subroutes, and contextual previews.
  6. 15:10 Infrastructure and Security Sebastian describes the separate front-end and back-office deployments, worker architecture, VPN protection, scaling, and plans for static content.
  7. 17:29 Multi-Tenant Localization The talk covers per-client database schemas, migration challenges, and the custom approach to enabling client-managed languages.
  8. 19:02 Wagtail Source-Code Extensions Sebastian demonstrates undocumented Wagtail components, Stimulus controllers, StreamField importing, tabs, and dynamic tokens in rich text.
  9. 22:08 Contributing to Wagtail The presentation concludes with the team’s efforts to stay current, submit patches, and participate in Wagtail core development.
  10. 23:33 Questions The discussion addresses admin-interface contributions, nonprofit onboarding, and the per-client deployment and database architecture.

Transcript

3,736 words · auto-generated Show

Automatically transcribed, so expect mistakes in names and technical terms.

0:00

Speaker 1: Hello everybody. I'm Ian. I'm the Chief Growth Officer for Wagtail at Torchbox and I'm delighted to introduce your next speaker, Seb Corbin from RGoods, who's going to talk to you about Building a SaaS platform for NGO donations on Wagtail. Over to you, Seb.

0:20

Speaker 2: Yes, uh, thank you. Um so hello everyone. I'm happy to welcome you in this presentation I'll hope we'll have time for a few questions at the end. There is a lot of content, lots of screenshots. And yeah, I'll be presenting our software as a service product, which we built on Wactail. And we'll see how we went from choosing it as a framework to how we maintain it every day. As for myself, my name is Sebastian. I'm a French developer. I'm also known on as a SEPCORBIN on the network. And I've been working in web development since I started studying. That was maybe 18 years ago. I'm coming from a PHP and Drupal background

1:08

Speaker 2: from where I discovered the power of open source community, but then I moved to Django and Python around 2016. So I work at AirGoods, a French company founded four years ago, and we are into what is called um CareTech. because we aim to work with one non-profit organizations by providing them digital solutions. Right now we have two products which are online shops and donation forms. I will take a few seconds to present the former as it's our historical product when the company was founded. It's a ready-to-use shop made with uh uh with WooCommerce

1:54

Speaker 2: from WordPress and uh has a label stuff white labeled sites And we have a whole team managing the sourcing of products, order logistics, customer service, etc. We focus on sourcing ethical products that are manufactured in Europe, sometimes branded for the NGOs, and the percentage of the sales goes directly to them. So also each of our stores is French. We have some internationally known clients like Doctors Without Borders, WWF, Amnesty International, and UN Women. But we are here to have a deep look at our second product, which is a donation form

2:42

Speaker 2: platform called AirGive. And here is a heads up on our main product features, so it's better to know how to better to know our clients' needs to understand the value of our SaaS. And when it comes to fundraising, our platform is designed to create campaigns that truly reflect the identity and values of our clients We make it easy to attract both one-time and regular donors. We try to prioritize the donor experience, ensuring it's simple, reassuring, and accessible for everyone. Flexibility is key, so we allow to customize the campaigns independently in a clear user-friendly interface Another key point is the importance of data management.

3:29

Speaker 2: So the data can be exported in various formats and integrated seamlessly in any CRM. Finally, we provide the freedom to configure payment methods for each campaign, ensuring that the process is as convenient as possible for the donors. So yeah, that was a long slide, but uh if you didn't want to read it, this is just a payment form. And you may ask me why launched that kind of product then? Well, there are a lot of solutions on the French and European markets. Among them is a historic player called Eraser, which represents about 80% of the French markets, at least for now. And I'm not talking about American companies like Donorbox, Fundraise

4:14

Speaker 2: Up, GiveButter, or even companies that are working in the UK. This is because the European market is strongly bound to the GDPR European regulation and those companies and solutions don't always apply GDPR-related regulations. Also, most of the solutions are focusing on having a freemium tier that is very limited in order to be available even for small NGOs. But at AirGoods we have decided to focus on medium to large NGOs and those ones need manual onboarding to closely match their brand and a tailored configuration to make sure they get all of their data for their CRM. And coming from a historic market, European donors will find a historic donor experience, which is called the three-column layout.

5:06

Speaker 2: But we wanted to move away from that and stand out, offer something new in terms of content. Because as you can see in the screenshot there, there is no Not so much explanation about the reason for giving. The whole layout is taken by the donation form in almost all of our concurrence solutions You have lit very little user interactions. It's very old school And another question that might be raised when calling out the simplicity of our product is why is it not internalized in NGOs? The answer is that very often not all of not a lot of resources are invested in this, especially in terms of IT.

5:51

Speaker 2: And an NGO might prefer to focus on communication and on their missions their actions. Also from an IT perspective, it's still quite complex and touchy. We know that the payment processing has ever-changing APIs and new regulations every other day So even ourselves have we are relying on a payment orchestrator called Norbear, which dispatches the payments on multiple platforms like Stripe, PayPal, Ogone. co -cardless and etc. So now I'll be talking about our choice of waktail for this product And starting with what you may already know, which are the features that Wagtails

6:38

Speaker 2: provide. And when came the time to choose the technology behind our product, we knew we wanted to work with Django because we love Python and we've been working with it for a long time. But when you start enumerating the basic feature of an editorial interface, you always end up with a WYSIWYG, a contribution workflow, a media library, and so on. And we didn't want to reinvent the wheel So we had a look at what Wagtail was offering, and we were surprised by its well-designed user interface, the stream field feature, and lots of other things that caught our eyes. And yeah, as I said, it's a Django. So we knew a way around making a Django project from our experience.

7:25

Speaker 2: But more importantly, like Django, Wagtail has packages, an ecosystem, an RFC system, a roadmap, etc. And a strong plus is that it was launched by TorchBox 10 years ago, which is oriented towards NGOs and sustainable development as well. And that was a strong sign for us. Among the clients of Torchebox are Mozilla, Oxfam, University of Pennsylvania, Royal College of Arts, etc. And by the way, Mozilla, for a time, they have their donation form on Wagtail. So isn't that curious? Well, we were really curious.

8:10

Speaker 2: So we went on to search if this was open sourced and we found the repo and we just clicked fork A defork button? No, of course not. And anyway, it seems that they switched to the fundraiser platform about a year ago No, instead we built the our product from the ground up. Well, kinda, because well you know we were starting with work telly, and we did it in uh in two and a half months to have a demo So now I'll be talking about what really stands out technically for a product. And again, it's a Django. So we kept our preferred Django packages and added them to the project. Most of them are really nice from a security perspective.

8:56

Speaker 2: And we had our first security audits this spring after a year of production and we've got a nice surprise because thanks to these packages, the report was very short. Regarding the user interface, it has improved a lot recently to be more compact and consistent. In our case, we need no tree structure. as most of the pages are either simple editorial pages or donation campaigns that can be considered as landing pages. So when we built the project, we started to heavily use the model admin country package first. And then it was closely followed by the universal listing migrations. And this universal listing feature

9:43

Speaker 2: makes it a joy to build administration interfaces because you can have bulk actions, secondary buttons, filters, search, crude actions, contextual buttons, secondary view. secondary views and so on. Another feature which you might know about is um but it's not that famous famous is the audit log As you may know, you can attach an history onto a model through the revision mix-in class so that every edit is saved. And you can see a diff of your changes between these edits. But what about system actions that may happen through automatic or scheduled background tasks?

10:28

Speaker 2: Well you can use for that purpose the audit log that allows to store custom events related to an instance. There is more information about how to implement it in the worktail documentation under the audit log section. And one of the features we use the most is the generic settings. These are singleton models that are exposed through a well-designed interface because of the headed handlers and they represent global settings that about your project. So you can make it configurable by your clients. It is pretty comparable to Django Constance except that they are not well cached and they are only cached through the current request.

11:15

Speaker 2: So if you multiply multiply these, you get a SQL query per singleton, so beware. And as the settings was one of the first features we implemented in our product, we made it so you can customize the site colors according to the client's brand colors. And we added the previewable mixing class to change to see changes live and this has quite a powerful effect during demos. We loved it, so there was a custom code that enabled it, but we decided to get it into a pull request, and that is one of our contributions to Wagtail 7. 1

12:00

Speaker 2: And continuing with colors, did you know that Wagtail Admin heavily relies on CSS variables, so you can override these variables according to each client's brand color, and it works even with dark mode enabled So I mentioned earlier the Streamfields feature. It's a killer feature for content editing, but it's also uh it can be also used for business needs. We use them as semi-structured JSON storage to guide configuration of dynamic objects For example, our export templates are built so that you can export in different formats

12:48

Speaker 2: like CSV, XML, JSON. And we know that each of these formats can have different parameters. So we built a block for each of them and exposed it in our configuration interface through a single stream field. That makes it really simple to edit. Continuing with exports, we allow to configure a lot of payment information to be exported. So in a CSV file they would be splitted into multiple columns. And each piece of data they have a different different types so they can be formatted in a different way

13:35

Speaker 2: through transformers that might themselves have parameters So again, we rely on StreamField to expose these transformers to blocks and at the end a single column is output as a Ginja template So as a result, our exports are very flexible As we made our campaigns a page model , this enabled to add technical subpages to this campaign. We made the post payment page a subroute through routable mixing so that you get the context of the campaign on the thank you page.

14:23

Speaker 2: We also use this sub route to make our campaigns display in a different mode, for example in an iframe, and it is very easy to implement. I mentioned the previewable mixing earlier. It's a thing we implemented on every model we could. So that it would show the final results, even for small widgets intended to be referenced, we would inject them in a more general context. And of course you can customize the preview modes as you can see in the screenshot on the bottom right. So we take this opportunity to show changes for subroutes of pages or even email templates

15:10

Speaker 2: or for different languages. always device always um uh device uh choose from mobile to desktop Okay, so now that we talked a bit about essential features of work tail, let me make a short presentation on our infrastructure. Our Django project can actually be booted with two sets of settings. One of them is a front with is which is targeted at donors. In this one we prevented including admin and login views so that we could protect them behind the VPN access.

15:55

Speaker 2: Hence the other one is the back office, which could be stopped. Meanwhile, the donation would be still be processed And this is one of the things that stand out in our security audit because no vulnerabilities were found on front-end facing URLs. To go deeper in this subject, here is our infrastructure schema. With these two sets of settings, we start at least three workers per client. One is the front for donation form with CDN for caching the statics that include a view component which calls the Django REST framework API. We can scale this one horizontally in case of a popular events

16:41

Speaker 2: organized by the client. One is the back office on which we upgraded our security around the login views and added VPN access. And the last one is dedicated to celery task launch in the background. But the final goal is to build a static version of the content pages that would be updated in the CDN to for each change. That would be made possible with Wagtail Bakery Package, for example, and then the Vue component would interact with an even more simplified version of the API worker. That could be based on FaceTapi or Django Ninja or anything else so as not to include Wagtail at all for the front end.

17:29

Speaker 2: So you may have read that Wagtail natively allows for multi-sites, but as a software, as a service, we have several clients and we don't want any data leak between clients. So we preferred uh having a single database schema per client for that end This brings a problem for migration handling because you need every schema to be the same. And as we allow our clients to activate new languages on their own We can't afford to have new deployments for new languages. So we did a bit of research for managing translations and the usual suspects are wact tail localize, which is useful when we're when you have a different page streak structure, but we don't use that.

18:17

Speaker 2: You also have um Wagtail Parlour, which uh which uses separate tables for translations. So again, we can't use that. And Wactel model translations, which creates a new column for each language for each field that is translated. So we can couldn't use any of these. Instead we decided to rely again on another Django package, which is Django Localized Fields, that converts char fields to HSTOR fields. This database type is a kind of like a dictionary where each value is actually a mapping of languages to their values.

19:02

Speaker 2: This is quite a custom development, but it allows to us for to translate a value either in a single language within a context or all languages at once Okay, so now I'm going to present features that are not necessarily taken from the Wagtail documentation, but by reading the source code. And the first one is LACES, which is a Django package that was extracted from Wagtail in a third-party package at the time Wagtail 6 came out. And actually the Wagtail documentation mentions laces and how to create your own components, so we decided to create some. One example is this user login log component, which uses a table class that already knows how to render itself.

19:50

Speaker 2: And this table component is not actually documented, but it's really easy to output a well-formatted well-formatted table that way, because it's the same as what model listings are using. Another thing that has a bit of documentation is stimulus, which Wachtel UI heavily relies on. There is currently a process supporting every bit of JavaScript code to stimulus and one of the reasons is to be CSP compliant and having no jQuery anymore. The goal is to include a controller that works on specific specific HTML markup and all parameters, actions and targets are specified as data attributes So yet uh you get an interactive UI

20:36

Speaker 2: only for a few lines of code. So now that you know What stimulus is for? What about controllers that are already included in Worktail? These are not documented, but you have to look at their source, which has documentation, to know how to use them. I've put up a few examples of them. And once you get your head around how they work, you can actually discover simple ways to reorder models in tables. We also added values importing in Streamfield through a custom adapter that uses stimulus to create a model with a progress button with not so much JavaScript needed. And finally, tabs are really great to organize information in inspect

21:23

Speaker 2: views. All of these were developed while relying on Wactail source code. And one last week that we managed to do is bring in that system of dynamic token in with transformers, the ginger syntax I mentioned earlier, into a draft tail plugin. That allows us to insert dynamic variables in WYSIWYG with the same features that in exports. This was maybe the hardest thing to develop as the draft tail has been abandoned by Facebook. And you have uh to make your way around the work tail documentation, the draft documentation, and draft JS examples. But here is the end result. Now, as we have been working with

22:08

Speaker 2: Wagtail for two years, we try to contribute back to it. So we've been involved in a few issues and pull requests. And we try to keep up with having a mention in the change log for each major release. So far, so good. To help with that, we aim to stay up to date with Wactel Core as much as possible. And it often brings new features like concurrent editing indicator and soon maybe autosave. So And also, the earlier you discover the bugs in core, the fastest their their fix will be accepted Forking Wagtail is complicated precisely because the controllers and the majority of the core JavaScript of Wagtail is compiled and this compilation is only done for releases.

22:55

Speaker 2: So we would have to maintain our own version, so we try to patch as much as possible waiting for the pull request to be merged, which has always always been been the case And thanks to all these contributions, the Wagtail Core team asked me if I wanted to join him earlier this year and I proudly said yes. So I hope you found this presentation interesting. And if we have a bit of time left, maybe five minutes, I'm happy to answer any question.

23:33

Speaker 1: Thank you, Seb. Really fascinating to hear about Wagtail used in a different context. We have a few questions. Uh first one, you you uh um just go back to your your finishing remarks there about joining the Wagtail core team. And you also earlier mentioned your contribution to Wagtail 7. 1. Which aspects of Wagtail product development and the the future roadmap are you most keen to focus on or contribute to as a member of the core team?

24:08

Speaker 2: Obviously it's the admin interface because as I've mentioned the view component but uh we are We have separated the API from the back end, from the back office. So we are really relying on Wagtail for the administration interface. So yeah, um I've closely followed the the universal listing and we are heavily using the model viewsets so sometimes we find some bugs or uh some um features that we would uh would implement in these so yeah that would be the the scope of uh of our contributions

24:53

Speaker 1: Thank you. Next question. When you uh obviously you work with lots of uh nonprofits, um when when you have a new nonprofit client, how long does it take to onboard them and get their donations form live? And are they self-sufficient from that point?

25:16

Speaker 2: For now they are not self-sufficient. We as I said we try to onboard them humanly with a human in front of them. So there is no automatic uh setup of in instance and uh I don't think we are ready to do that uh anyway because um well you have to Even though the interface is um is quite uh simple, you have to know where you you go to uh where you need to go to configure your your instance and in a specific order. So for example you you'll try to set up the colors then the content and then you have to uh make your uh your payment processing work

26:03

Speaker 2: as uh soon as possible before the go live and there is also the go live um uh well events uh which is uh closely linked to DNS propagation on the on large website it is quite touchy so we try to make it human on that uh on that uh side

26:27

Speaker 1: Thanks. And just just one more question before we finish up. Is it correct that each customer has their own database? Does the Wattel backend run separately for each customer or is it shared?

26:43

Speaker 2: Well, we have three workers per client. So this is a this is a fact for now. We may have multi-tenancy on the Python workers uh later but uh yeah as i said maybe uh quite uh rapidly uh each client has its own schema so the the we do we we have a separated a separated database schema on um for each client i hope that answers the question

27:21

Speaker 1: Thank you, Seb. That's that's all the questions. Uh thank you very much for sharing your work with us. Really interesting stuff. It's 28 minutes past, so uh we'll uh move on now if uh uh if everyone goes back to the lobby to find their next session. Um and thanks again, Seb. Really appreciate it

27:42

Speaker 2: Choin

Questions this talk answers

Why don’t NGOs build their own donation forms in-house?

NGOs often have limited IT resources and prefer to focus on communications and their mission. Payment processing is also technically sensitive because APIs and regulations change frequently, so the platform relies on a payment orchestrator to handle multiple providers.

Discussed at 5:51

Why use Wagtail to build a SaaS donation platform?

The team already wanted Django and did not want to rebuild common editorial features such as WYSIWYG editing, workflows, and media management. Wagtail’s interface, StreamField, ecosystem, NGO focus, and Django foundation made it a strong fit.

Discussed at 6:38

How does the Wagtail donation platform support flexible data exports?

It uses StreamField blocks to configure CSV, XML, and JSON export formats, including payment fields and parameterized transformers. The resulting columns can be rendered from Jinja templates, making exports adaptable to different CRM requirements.

Discussed at 12:48

How is a Wagtail SaaS application secured and scaled?

The application separates the donor-facing frontend from the back office, keeping administration and login views behind VPN access. Each client has frontend, back-office, and Celery workers; the frontend can scale horizontally behind a CDN for high-traffic fundraising events.

Discussed at 15:10

How do you isolate customer data in a multi-tenant Wagtail SaaS?

Rather than relying on Wagtail multisite, the platform uses a separate database schema for each client to prevent data leaks. It currently runs three workers per client, although the team may introduce shared Python workers later.

Discussed at 17:29

How does the platform handle translations when customers can add languages themselves?

The standard Wagtail translation packages did not fit the requirement because they would complicate schema management or use separate translation structures. The team instead uses Django Localized Fields, storing language-to-value mappings in HStore fields and allowing values to be translated per language or across all languages.

Discussed at 18:17

How are new nonprofit clients onboarded to the donation platform?

Clients are not yet self-service; the team onboards them manually. They guide the client through configuring brand colors, content, payment processing, and the go-live process, including DNS propagation.

Discussed at 25:16

Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.

More videos from Wagtail Space