A Fundraising Platform built on top of CiviCRM

2011-10-15 16:52
Written by

As most non-profits know, driving revenue exclusively off of events can be a hit or miss adventure.  Revenues YOY are not consistent, and its difficult to find those supporters who will organize and host fundraising events to support your cause.  Many are intimidated by hosting large fundraisers or simply don't have the time or resources to pull it off.  So to sum up our problem: we needed a broader more consistent source of revenue to fund our programs.     To expand our source of revenue, we looked to our community of donors, families, and fundraisers to raise money on our behalf through their own social networks.  The average user on facebook has 30 friends [http://www.facebook.com/press/info.php?statistics] which means that we could exponentially increase our reach through online social networking interaction.  All we needed was to setup the campaign pages platform and get people started.

The concept of online fundraising through personal campaign pages is certainly not new.  There are a number of services out there that allow non-profits and their fundraisers to setup campaigns and pages and all of them have their strengths and weaknesses.  For both of our non-profits, none of them met our specific objectives which were:

  1. Integration with our existing donor management system, CiviCRM
  2. Ability to brand and customize the experience to our specific campaigns
  3. Allow us to apply gamification elements to the campaigns
  4. Allow us to support international campaigns (specifically for FPWR's OneSmallStep Walk-Run)
  5. Give us the flexibility to continue to enhance and expand the system over time

FPWR Fundraising Platform

Why CiviCRM and what was it lacking out of the box?

Both PWSA and FPWR are long time CiviCRM users and have been managing online and offline fundraising through the system for many years.  In fact, even before CiviEvent was introduced, we were using custom CiviContribute pages wrapped in WebForms to create an integrated event donation experience.  We have years of donor data in the system and we wanted to continue to build upon that with this system.  Moreover, we like CiviCRM: the price is right and the support is fantastic.  

How is this designed?  

We developed a series of Drupal modules that connect the fundraising system to a CiviCRM backend.  These two components do not need to live on the same machine, and in fact, we ran the PWSDerby site on a completely separate machine and host.  The modules configure access to CiviCRM and also control the settings related to the campaign.  Campaigns in the system are mapped to contribution types within CIVICRM.  For a multi-location campaign, we actually have multiple contribution types constructed and we piece them together on the front end.  

A Technical Explanation

When a node of type dw_campaigns_deby is created in drupal it creates a contribution page and a contribution type to match that node’s "title", we also create a pcpblock at the same time (pcp blocks just have some extra configuration data which maps 1:1 with a contribution_page).   We then store this new contribution pages id in a lookup table in drupal so we can map node id  X to contribution page Y.    When a user signs up in drupal, we prompt them for some additional info and create a PCP for that user which we associate with that contribution page id.

The platform was built on Drupal 6 with CiviCRM 3.3.1 and the v2 APIs.  Next year, we expect we will upgrade these to newer versions after our fundraising season is over.

So what was CiviCRM lacking?  

Out of the box it allowed us to create a contribution (campaign) page and attach personal pages to it, but the usability and flow of how those get setup and managed was missing.  We wanted to build a simple, integrated, user experience that would make it easy for our fundraisers and donors.  This required that we create a completely separate web experience that would connect to CiviCRM through APIs.  In other words, we wanted to brand and customize the experience.


First, we identified the primary users that would interface with the system:  donors, fundraisers (page owners) and wrote the primary stories on what each would need to do within the system.  From this, we developed a series of wire frames on how the system should look and function.  Our usability objectives were as follows:

  1. Donors
  1. Quickly find the fundraising page for the individual they wish to support and make a donation to that page.  Follow up with a thank you email/receipt.
  1. Fundraisers
  1. Make it simple to create a fundraising page, share that page with their social networks, and track progress of their fundraising effort.
  1. Non-Profits
  1. Create a dashboard view of the fundraising campaign (thermometer, leader boards to drive competition) and provide a centralized configuration interface for campaign management.

To accomplish these objectives, we built in the following features:


  1. Search boxes to find fundraising pages by name or location
  2. Leaderboards showing top donors in each location
  3. Large "donate now" buttons that presented a simple form for the user to donate to a page
  4. EMail templates that allowed us to customize receipt text on a per-campaign basis

SCREEN SHOT: Donation Page

SCREEN SHOT:  Leaderboards


  1. Simple "Create a Page" form that guided the user through the process of setting up their page, uploading a photo (or attaching a video), writing their description and sharing their page with their social networks.
  2. Facebook Like Buttons on fundraising pages, share on Facebook
  3. Email notifications when people have donated to their page

SCREEN SHOT: Share on Facebook Wall



  1. Drupal module that connects this fundraising system with a CIVICRM backend.  This backend can run anywhere provided there is Internet connectivity (drupal to CiviCRM API) between the two systems
  2. Centralized campaign configuration with the ability to customize aspects of the site (email replies, receipts, text on the pages) through tokens (variables)


Our experience has been a success. We have been able to process over $500,000 through the system in just the few short months we have had it running.  Looking at the ROI, we saved roughly 5% off of using a commercial alternative and were able to customize this to our exact liking.  That 5% is approximately $25,000 which pays for the development (1 year payback) and gives us a platform to use moving forward.   With all of this said, we did have a few Gotcha's that we want to make people aware of. Call them lessons learned or just things that we had to manage through the process.  They are listed in the next section


  1. Handling of payments between CiviCRM and PayPal (Website Payments Pro) and the user.    When a user hits the submit payment button we would make a REST api call to the CiviCRM backend which would then contact Paypal to process the donation.   Since this wasn’t cachable and often required several API calls, the time duration could get up to a few seconds.  If the user felt as it it was not working, they would hit the payment button again.  This would result in multiple charges in Paypal (and only a single record in CiviCRM).  
  1. To solve this, we disable the "pay now" button after its initially pressed until the transaction is complete where we then share the results with the user.  We also display a lightbox informing the user not to navigate away or to refresh  
  1. Debit cards through Paypal.  For some reason we can't explain, credit cards that also serve as debit cards can error out in PayPal.  We return the error to the user and they would end up trying again.  Each debit transaction results in a hold on the users account which can take a few business days to clear.  This would concern donors who felt they had donated multiple times as their account had shown a debit for each of the transaction attempts.  This issue resolves itself after a few days when the holds are lifted, but in the meantime it results in emails and phone calls from concerned donors.  
  1. International Donations into PayPal .   Its best if you have a local entity in each country in which you intend to fundraise.  That is the case for us for the US and Canada, and the system allows us to specify specific payment processors for each event location (e.g. an event in Canada can be processed through our Canadian payment processor and the donations sent to our Canadian affiliate).  However, for some places in Europe, the donations and transactions were sent to us in the United States.  This resulted in a number of transactions sitting in PayPal waiting to be marked as approved.  
  1. In the beginning, we didn't realize that we had to do this.  To get around it, we setup multiple currency accounts in PayPal.  This allows us to choose when we convert funds to US Dollars.  We then set our account to automatically accept donations in multiple currencies so we didn’t have to login to manually accept them.  This eliminated the need to accept payment and the potential of losing payments if not monitored regularly.
  1. REST API Latency.   This was built on the CiviCRM v2 API.  The v2 REST API has higher latency for queries vs local Api calls.  This should be obvious to most and at first it doesn't seem to be that big a deal.  But when you start having busy pages which require lots of lookups the difference in time really adds up and can hurt the user experience.   We implemented a caching system (on the drupal side) so that we didn't have to look up the exact same data everytime someone went to a page.

  1. Legacy Code.  A portion of this project was actually a port of a previous project which used a local copy of civi crm, there were places where we'd directly interfaced with the db or had used non exposed functions.   We should of created new API functions to access the db and to expose the needed functions.  So code it like you're going to be interface agnostic.
  1. Efficiency.  If you need to look up data that you'd normally use a "join" for think about adding an api call which does the join for you, rather then looking up one table and looping to look up the data from the "joined" table.  The same goes for accumulating totals (sum).  We realized this too late in the project, so we lean on the cache more then we'd like.
  1. Error Condition - Empty Results.  This was actually a big one because it would break the system due to our caching approach if we didn’t catch it.  Plan for empty results.  Using the Civi REST api has been pretty smooth, but when a network issue comes up and the remote civi is unavailable be preparred to receive no data.  And also be sure not to cache this empty result. :-)
  1. Changing Contact IDs.   Contact ids can change.  For our project we store locally a lookup table for drupal id -> civi ids.  We chose not to use the built in civicrm_uf system because we were uncomfortable with having to set up domain_ids and we have multiple sites all interfacing with the same backend which means we could have 3 different people with a drupal id of "10" that need to map to different civi contact ids.   This worked great until it came time to dedupe the contact list.  Some contacts changed ids because they were active in other projects before this site even existed, normally civi would manage all of this, but civi unfortunately can't change our remote db to keep it in sync.  So, we wrote a little drupal module called civicrm_merge_catch which we run on the civi drupal installation and have it notify the public site.

function civicrm_merge_catch_civicrm_merge($type, &$data, $mainId = NULL, $otherId = NULL, $tables = NULL) {

if($type == 'sqls') {

// do your call back here - otherId is the id being changed, mainId is the "new" contact id



We wanted to stop where we are and share our experience and source code with the community, but we also intend to improve upon it (and hope that you do as well).  Some additional things we would like to do:

  1. Continue to drive gamification elements into the system.  This can include badges for reaching certain levels, virtual goods (e.g. Trophies) for specific awards or accomplishments (e.g. recruiting most people, raising most in a week, team awards, etc.)
  2. Continue to clean up the administrative aspects of it to make it easier for CiviCRM-based non-profits to use it
  3. Deeper social integration so that fundraisers can tweet or update their facebook status with their progress and donors can update status regarding their donations
  4. Mobile web views of campaign and landing pages
  5. More robust thank you system so that fundraisers can send out thank you notes and track them with their donors.

Any other ideas?  Let us know!

Finally, if you have any questions or need more information, don't hesitate to ask and we will do our best to answer them.


Play with it

Feel free to check out the website at http://onesmallstep.fpwr.org or http://www.pwsderby.com (both are running off of the same system).  

“GIT it”

In addition, you can access the source code for it at our GIT repository here:  https://github.com/fpwr/Fundraising-Campaigns  CAUTION! There may be some places in the code where things are referenced as FPWR, PWS, Derby, Walking, etc.  If you can live with those, great, otherwise, these references and files will need to be modified for your own needs.  


Please post questions regarding the code or what we are doing at our GitHUB repository or contributing to our WIKI page.   That WIKI page is part of our GIT repository and can be found here:  https://github.com/fpwr/Fundraising-Campaigns/wiki

Need help or assistance setting this up?

We have a set of talented developers that built this platform and can be hired to help you build your site.  Please contact me at jeff.porter[at]fpwr[dot]org if you are interesting in talking further.

Good luck!

Jeff Porter, Ryan Johnson, Susan Hedstrom, Foundation for Prader-Willi Research (FPWR)


Hey Jeff - this sounds like an awesome project. I remember your presentation at SanFran in 2008 (?) and being impressed then - and this really adds a layer of coolness on to all the work you have done.
The gaming aspect is definitely useful - we had to do one for a 'walk to work week' so each team could add up the collective distance they walked - gently competitive ;-)
Good listing of the 'gotchas' that will help others think their way around these problems before hitting them.
Best of luck with meeting your fundraising goals and thanks for making the code available.

This is a really neat system, and it's impressive the amount of work that went into making it so smooth. Given the opportunity I would love to adapt this to another site. I have a client that uses a 'mostly' out of the box PCP solution in CiviCRM currently, I will ask them about it. Thanks for publishing your work for the rest of the community to see and use.

Colin (not verified)
2011-11-01 - 21:50

Looks great.

Would be great to give users the ability to see previous campaigns.

Colin (not verified)
2011-11-02 - 08:48

I registered on the onesmallstep site and received an email containing my password in unencrypted plain text. Not an acceptable practice for any organization taking privacy\security seriously.

Hello Jeff, 


Would you have installation/deployment instructions to get the code deployed in a sandbox for testing/development? I would like to install the code you shared on github but couldn't find any installation instructions available.


Thanks in advance,



I have a client that needs something like this.  Can we hire you to help?



Wow, really impressive. I'm building a site for an organization that is fighting to stomp out child abuse...been hoping that CiviCRM would eventually become this. Unfortunatly, we've built the site on Joomla and do not have the time to rebuild a Drupal site.

May consider this for next year,unless a Joomla version becomes avaialble sooner.

Great Work!

Hi Jeff,

I stumbled across this when looking for ways to improve CiviCRM's Personal Campaign Pages for a client - it seems to offer a lot of what they want, but it seems to be very geared toward fundraising events, whereas this client just has a number of different funds they want people to be able to raise money for, without it being linked to an event. Is that possible with this system?

It is - as we don't use CiviEvent at all in this system. However, we do setup locations as campaigns (although those locations could be skinned as just projects or other initiatives).  PM if you want to discuss this further.