How to attach anonymous data to existing user after they log in?

I ran into exactly this recently and solved it with a simple cookie (read on for deets).

As you note, for new users it works fine to save data to the “Current User” which then gets attached automagically when that anonymous user converts to a registered user – at least within the lifetime of the cookie/anonymous user in the database [something like 3 days, I believe?].

However, this does not magically work for an existing registered user who visits your site, does some stuff, and then later in the session logs in. This is particularly problematic if you are using OAuth authentications as your page is going to be reloaded after authentication is complete – so the state of things on the page will be reset.

In my case (a reservations type site), I wanted to make it so that we don’t force the user to log in before they start to make an inquiry/reservation. However, we want to log them in or register them at some point in that workflow. So this is a nice, bounded problem that’s perfect for a session cookie.

Here’s the most “bubbly” way I could think of to solve this issue:

  1. When a non-logged-in user goes to submit an inquiry, we continue to store info on the user, however, we also create a new database object. In my case, I call this a “Temporary Inquiry” which stores all of the data we will need to reconstruct the state of the inquiry after the user logs in. (In my case, this is stuff like dates they’ve selected, what listing it is they are inquiring about, the number of guests, etc.)

  2. We grab the unique ID of that new object and store that unique ID in a session cookie. So this is super-lightweight, right? Just a simple text string (but it points to an object in the database that could actually be very, very complex).

  3. If the page is reloaded and there is data in this session cookie, we know that the user was in the process of making a reservation and we can rebuild the state of that inquiry for them so they can continue where they left off.

Here are the details of how I implement that:

COOKIE

The library I’m using for this is js-cookie, which is super-simple and easy to use (and has defaults that perfectly match this type of use case). That library is documented here: js-cookie - npm

To use it, we will need the toolbox plugin (so we can Run Javascript) and we will also need to include the library on our page. So, in an HTML element, we include js-cookie like this:

<script src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.2.0/js.cookie.min.js"></script>

Syntax is super simple as you can see from the docs page I link to above. For example, to set a session cookie for the site, we just call:

Cookies.set('name', 'value');

Creating the Temporary Thing and Storing its ID in a Cookie

Here’s an example of a workflow. What’s highlighted here is what happens when a non-logged-in user clicks the submit button in my inquiry widget:

Step 1. I’m still saving some data on Current User (in my case this is more-or-less optional now, but it’s not hurting nobody, right?)

Step 2. Create a New Thing in the database (in my case, it’s all the reservation data they’ve input, along with the unique ID of this “listing” page). If you wanted to get fancy, you could, add a step after here to schedule a workflow to delete this temporary item at some point in the future.

Step 3. Run javacript to set the cookie. The contents of that step look like this:

The first line just echoes data to the console for debug purposes. The second line is where the action happens:

Cookies.set('SIID'), '_unique ID of the thing we created in step 2_');

That creates a site-wide session cookie called “SIID” (“Submitted Inquiry ID”, see?) which contains a text that is the Temp Inquiry’s unique ID in our database.

Step 4. It’s now safe to display the Signup/Login Popup.

Restoring the Inquiry State on Page Reload

Depending on how the user signs up or logs in, the page might be reloaded and we might need to pick up where the user left off. To handle that, we do this:

Step 1. Run javascript to read the cookie. The action here takes place in lines 2 and 3. Line 2 reads the cookie and shoves its value (which, remember is just a text value of the Temp Inquiry’s unique ID). Line 3 pushes that value back to Bubble using the JavaScript to Bubble element (also part of the “Toolbox” plug-in).

The JS to Bubble element is configured on my page like this:

When we execute bubble_fn_cookie(value); that value is published back to Bubble as element “JS Cookie’s value”.

You may be wondering: What if the cookie does not exist? Well, if that’s the case, js-cookie just returns a value of undefined (what in Bubble terms is called “is empty”). So again that library is perfect for our use case.

Step 2. I fire off a Custom Event called “Restore Submitted Inquiry”. This custom event is configured as taking a thing of type “Temp Inquiry”. We find it in the database this way: We “Do a Search for… Temp Inquirys… where the Temp Inquiry’s unique ID is equal to what we got back from the cookie”. That search will return a list, of course, but it will only have 1 item in it (hence “:first item” appended to the end):

The “Only When” condition is to handle the following issue:

  1. I’m not being fancy with this cookie. It only stores a single value (though it could have been an array of values or whatnot) and only one will exist for the session. So we can be guaranteed that this cookie represents ONLY this user. Further, if we find a value here (it’s not undefined/empty) the user did reach the point of submitting an inquiry and we should reconstruct their inquiry so they can finish submitting it.

  2. However, what we don’t know is this: The user may have hit this point ON A DIFFERENT LISTING PAGE. Imagine that the user looked at Listing A and started to submit their information. They clicked submit and then, when presented with the login/sign-up pop-up, they abandoned the inquiry. However, they then continued to Listing B.

  3. So, we need to check that their Temp Inquiry is about the Listing that is related to THIS page. When I create the Temp Inquiry, one of the pieces of info in it is the Listing that the inquiry relates to. So here, we trigger the “Restore Submitted Inquiry” custom event ONLY WHEN… The Temp Inquiry’s Listing ID is equal to THIS Page’s Listing ID.

My custom event (“Restore Submitted Inquiry”) looks like this:

You’ll note that (even though I also did this in the trigger) I put an “Only When…” condition here so that, if the workflow thing (Temp Inquiry) is empty, we don’t bother trying to do all of this stuff. All of the workflow steps are just all of the things I need to do to reconstruct the state of the page/user’s in-progress inquiry.

After all of that is complete, the user (who is now Logged In) can complete their inquiry.

When they do, I execute the following workflow. Now they are Logged In, and clicking the Submit button will create a full-fledged inquiry associated with the logged in user and we can clean up the temp stuff and cookie (should we desire and should they exist):

The relevant steps are these:


Again, just a simple function call deletes the cookie (which, because its a session cookie, will be deleted when the user ends their session / closes the browser anyway… depending on your use case you might want to keep the cookie around for the rest of the session… but in my use case I’m done with it and so we remove it).

While the above is very specific to my use case, I’m sure you can imagine many scenarios where this general technique would be useful.

Session cookies in particular are so useful that I am A BIT surprised that there’s not a built-in Bubble element / workflow actions to do simple cookie tricks like this, but with js-cookie being so simple to use, it’s practically the same thing.

Aside: the Run Javascript action and the JS to Bubble element from the Toolbox plug-in are super-handy! Once you understand the basics of using them (and the example above is enough to get you started, for sure), the palette of things you can do in Bubble expands greatly.

Most of what I use them for is executing very simple little scripts like this.

36 Likes