Multisite support for Sitecore JSS – Next.js using Vercel’s Edge Middleware – Demo on Sitecore Demo Portal (XM + Edge)!

I’ve come across the requirement for supporting a multi-site Sitecore-SXA approach with a single rendering host (Next.js app).

With this approach, we want to lower the costs by deploying to a single Vercel instance and making use of custom domains or sub-domains to resolve the sites.

If you have a look at the Sitecore Nextjs SDK and/or the starter templates, you’ll notice that there is no support for multi-site, so here I’ll go through a possible solution for this scenario where we need also to keep the SSG/ISR functionality from Next.js/Vercel.

The approach

To make it work we basically need to somehow resolve the site we’re trying to reach (from hostname or subdomain) and then pass it through the LayoutService and DictionaryService to resolve those properly.

As we’ve also enabled SSG, we’ll need to do some customization to the getStaticPaths so it generates the sitemap for each site.

Resolving the site by custom domains or subdomains

As I mentioned in the title of the post, I’ll be using Edge Middleware for that, so I’ve based this on the examples provided by Vercel, check the hostname-rewrites example!

For more details on Edge Middleware, please refer to my previous post!

Dynamic routes

Dynamic Routes are pages that allow you to add custom parameters to your URLs. So, we can then add the site name as a param to then pass it through the layout and dictionary services. For more details on dynamic routing, check the official documentation and the example here!

Demo!

We now know all the basics, let’s move forward and make the needed changes to make it work.

For demoing it, I’m just creating a new Sitecore Next.js JSS app by using the JSS initializer and the just recently released Sitecore Demo Portal! – Check this great blog from my friend Neil Killen for a deep overview of it!

Changes to the Next.js app

To accomplish this, as already mentioned, we have to play with dynamic routing, so we start by moving the [[…path]].tsh to a new folder structure under ‘pages’: pages/_sites/[site]/[[…path]].tsh

Then we’ve to create the middleware.ts file in the root of src. The code here is quite simple, we get the site name from the custom domain and then update the pathname with it to do an URL rewrite.

import { NextRequest, NextResponse } from 'next/server'
import { getHostnameDataOrDefault } from './lib/multisite/sites'

export const config = {
  matcher: ['/', '/_sites/:path'],
}

export default async function middleware(req: NextRequest): Promise<NextResponse> {
  const url = req.nextUrl.clone();
  // Get hostname (e.g. vercel.com, test.vercel.app, etc.)
  const hostname = req.headers.get('host');

  // If localhost, assign the host value manually
  // If prod, get the custom domain/subdomain value by removing the root URL
  // (in the case of "test.vercel.app", "vercel.app" is the root URL)
  const currentHost =
    //process.env.NODE_ENV === 'production' &&
    hostname?.replace(`.${process.env.ROOT_DOMAIN}`, '');
  const data = await getHostnameDataOrDefault(currentHost?.toString());

  // Prevent security issues – users should not be able to canonically access
  // the pages/sites folder and its respective contents.
  if (url.pathname.startsWith(`/_sites`)) {
    url.pathname = `/404`
  } else {
    // rewrite to the current subdomain
    url.pathname = `/_sites/${data?.subdomain}${data?.siteName}${url.pathname}`;
  }
  
  return NextResponse.rewrite(url);
}

You can see the imported function getHostnameDataOrDefault called there, so next, we add this to /lib/multisite/sites.ts

const hostnames = [
  {
      siteName: 'multisite_poc',
      description: 'multisite_poc Site',
      subdomain: '',
      rootItemId: '{8F2703C1-5B70-58C6-927B-228A67DB7550}', 
      languages: [
        'en'
      ],
      customDomain: 'www.multisite_poc_global.localhost|next12-multisite-global.vercel.app',
      // Default subdomain for Preview deployments and for local development
      defaultForPreview: true,
    },
    {
      siteName: 'multisite_poc_uk',
      description: 'multisite_poc_uk Site',
      subdomain: '',
      rootItemId: '{AD81037E-93BE-4AAC-AB08-0269D96A2B49}', 
      languages: [
        'en', 'en-GB'
      ],
      customDomain: 'www.multisite_poc_uk.localhost|next12-multisite-uk.vercel.app',
    },
]
// Returns the default site (Global)
const DEFAULT_HOST = hostnames.find((h) => h.defaultForPreview)

/**
 * Returns the data of the hostname based on its subdomain or custom domain
 * or the default host if there's no match.
 *
 * This method is used by middleware.ts
 */
export async function getHostnameDataOrDefault(
  subdomainOrCustomDomain?: string
) {
  if (!subdomainOrCustomDomain) return DEFAULT_HOST

  // check if site is a custom domain or a subdomain
  const customDomain = subdomainOrCustomDomain.includes('.')

  // fetch data from mock database using the site value as the key
  return (
    hostnames.find((item) =>
      customDomain
        ? item.customDomain.split('|').includes(subdomainOrCustomDomain)
        : item.subdomain === subdomainOrCustomDomain
    ) ?? DEFAULT_HOST
  )
}

/**
 * Returns the site data by name
 */
export async function getSiteData(site?: string) {
  return hostnames.find((item) => item.siteName === site);
}

/**
 * Returns the paths for `getStaticPaths` based on the subdomain of every
 * available hostname.
 */
export async function getSitesPaths() {
  // get all sites
  const subdomains = hostnames.filter((item) => item.siteName)

  // build paths for each of the sites
  return subdomains.map((item) => {
    return { site: item.siteName, languages: item.languages, rootItemId: item.rootItemId }
  })
}

export default hostnames

I’ve added the custom domains I’d like to use later to resolve the sites based on those. I’ve defined 2 as I want this to work both locally and then when deployed to Vercel.

Changes to the getStaticProps

We keep the code as it is in the [[…path]].tsx, you’d see that the site name is now part of the context.params (add some logging there to confirm this)

[[…path]].tsx

Changes to page-props-factory/normal-mode.ts

We need now to get the site name from the context parameters and send it back to the Layout and Dictionary services to set it out. I’ve also updated both dictionary-service-factory.ts and layout-service-factory constructors to accept the site name and set it up.

normal-mode.ts
fictionary-service-factory.ts
layout-service-factory.ts

Please note that the changes are quite simple, just sending the site name as a parameter to the factory constructors to set it up. For the dictionary, we are also setting the root item id.

Changes to getStaticPaths

We have now to modify that in order to build the sitemap for SSG taking all sites into account. The change is also quite simple:

// This function gets called at build and export time to determine
// pages for SSG ("paths", as tokenized array).
export const getStaticPaths: GetStaticPaths = async (context) => {
  ...

  if (process.env.NODE_ENV !== 'development') {
    // Note: Next.js runs export in production mode
    const sites = (await getSitesPaths()) as unknown as Site[];
    const pages = await sitemapFetcher.fetch(sites, context);
    const paths = pages.map((page) => ({
      params: { site: page.params.site, path: page.params.path },
      locale: page.locale,
    }));

    return {
      paths,
      fallback: process.env.EXPORT_MODE ? false : 'blocking',
    };
  }

  return {
    paths: [],
    fallback: 'blocking',
  };
};

As you can see, we are modifying the fetcher and sending the site’s data as an array to it so it can process all of them. Please note the site param is now mandatory so needs to be returned in the paths data.

Custom StaticPath type

I’ve defined two new types I’ll be using here, StaticPathExt and Site

Site.ts
StaticPathExt.ts

We need to make some quick changes to the sitemap-fetcher-index.ts now, basically to send back to the plugin the Sites info array and to return the new StaticPathExt type.

import { GetStaticPathsContext } from 'next';
import * as plugins from 'temp/sitemap-fetcher-plugins';
import { StaticPathExt } from 'lib/type/StaticPathExt';
import Site from 'lib/type/Site';

export interface SitemapFetcherPlugin {
  /**
   * A function which will be called during page props generation
   */
  exec(sites?: Site[], context?: GetStaticPathsContext): Promise<StaticPathExt[]>;
}

export class SitecoreSitemapFetcher {
  /**
   * Generates SitecoreSitemap for given mode (Export / Disconnected Export / SSG)
   * @param {GetStaticPathsContext} context
   */
  async fetch(sites: Site[], context?: GetStaticPathsContext): Promise<StaticPathExt[]> {
    const pluginsList = Object.values(plugins) as SitemapFetcherPlugin[];
    const pluginsResults = await Promise.all(
      pluginsList.map((plugin) => plugin.exec(sites, context))
    );
    const results = pluginsResults.reduce((acc, cur) => [...acc, ...cur], []);
    return results;
  }
}

export const sitemapFetcher = new SitecoreSitemapFetcher();

And last, we update the graphql-sitemap-service.ts to fetch all sites and add its info to get returned back to the getStaticPaths

async exec(sites: Site[], _context?: GetStaticPathsContext): Promise<StaticPathExt[]> {
    let paths = new Array<StaticPathExt>();
    for (let i = 0; i < sites?.length; i++) {
      const site = sites[i]?.site || config.jssAppName;
      this._graphqlSitemapService.options.siteName = site;
      this._graphqlSitemapService.options.rootItemId = sites[i].rootItemId;
      if (process.env.EXPORT_MODE) {
        // Disconnected Export mode
        if (process.env.JSS_MODE !== 'disconnected') {
          const p = (await this._graphqlSitemapService.fetchExportSitemap(
            pkg.config.language
          )) as StaticPathExt[];
          paths = paths.concat(
            p.map((page) => ({
              params: { path: page.params.path, site: site },
              locale: page.locale,
            }))
          );
        }
      }
      const p = (await this._graphqlSitemapService.fetchSSGSitemap(
        sites[i].languages || []
      )) as StaticPathExt[];
      paths = paths.concat(
        p.map((page) => ({
          params: { path: page.params.path, site: site },
          locale: page.locale,
        }))
      );
    }
    return paths;
  }

We’re all set up now! Let’s now create some sample sites to test it out. As I already mentioned, I’m not spinning up any Sitecore instance locally or Docker containers but just using the new Demo Portal, so I’ve created a demo project using the empty template (XM + Edge). This is really awesome, I haven’t had to spend time with this part.

Sitecore Demo Portal

I’ve my instance up and running, and it comes with SXA installed by default! Nice ;). So, I’ve just created two sites under the same tenant and added some simple components (from the JSS boilerplate example site).

Sitecore Demo Portal instance

From the portal, I can also get the Experience Edge endpoint and key:

Sitecore Demo Portal

Note: I’ve had just one thing to do and I’ll give feedback back to Sitecore on this, by default there is no publishing target for Experience Edge, even though it comes by default on the template, so I’ve to check the database name used in XM (it was just experienceedge) and then created a new publishing target.

The first thing is to check the layout service response gonna work as expected, so checked the GraphQL query to both XM and Experience Edge endpoints to make sure the sites were properly resolved.

From XM: https://%5Bsitecore-demo-instance%5D/sitecore/api/graph/edge/ui

GraphQL playground from XM

From Experience Edge: https://edge-beta.sitecorecloud.io/api/graphql/ide

GraphQL playground from Experience Edge

All good, also checked that the site ‘multisite_poc_uk‘ is also working fine.

Now, with everything set, we can test this out locally. The first thing is to set the environment variables so those point to our Experience Edge instance.

  • JSS_EDITING_SECRET: (from Demo Portal)
  • SITECORE_API_KEY: (from Demo Portal)
  • SITECORE_API_HOST=https://edge-beta.sitecorecloud.io
  • GRAPH_QL_ENDPOINT=https://edge-beta.sitecorecloud.io/api/graphql/v1
  • FETCH_WITH=GraphQL

Let’s run npm run start:connected in our src/rendering folder!

Note: I’ve added hosts entries to test this out locally:

127.0.0.1 www.multisite_poc_global.localhost
127.0.0.1 www.multisite_poc_uk.localhost
npm run start:connected

If everything went well, you should be able to see that (check the logging we added in the getStaticProps previously).

UK Site
Global Site

Cool! both sites are properly resolved and the small change I’ve made to the content bock text confirms that.

Let’s now run npm run next:build so we test the SSG:

npm run next:build

Deploying to Vercel

We’re all set to get this deployed and tested in Vercel, exciting!

I won’t go through the details on how to deploy to Vercel as I’ve already written a post about it, so for details please visit this post!

Couple of things to take into account:

  • I don’t push my .env file to the GitHub repo, so I’ve set all the environment variables in Vercel itself.
  • I’ve created 2 new custom domains to test this. Doing that is really straightforward, in Vercel got to the project settings, and domains and create those:
Vercel custom domains

I’ve pushed the changes to my GitHub repo that is configured in Vercel so a deployment just got triggered, check build/deployment logs and the output!

Looking good! let’s try out the custom domains now:

https://next12-multisite-global.vercel.app/

Global site

https://next12-multisite-uk.vercel.app/

UK site

I hope you find it interesting, you can find the code I’ve used for this example in this GitHub repo.

If you have a better or different approach to resolve multisite within a single Next.js app, please comment! I’d love to hear about other options.

I’d like also to say thanks to Sitecore for this Portal Demo initiative, it’s really helpful to speed up PoC and demos to customers!

Thanks for reading!

Start your commerce solution in minutes with Vercel, Next.js Commerce template, and the new Sitecore OrderCloud® integration – Part I

In this post, I’ll describe the steps to get a full development environment from scratch, using the Next.js Commerce template integrated with OrderCloud and deploying to Vercel.

Sitecore OrderCloud®

Sitecore OrderClooud is an API-First, headless cloud platform for B2B, B2C, and B2X commerce solutions. It powers custom e-commerce experiences, order management, and B2B marketplace applications for some of the world’s most well-known brands.

If you don’t have your account yet, go here and create one, you can sign up for free!

Vercel – Next.js Commerce

Next.js Commerce is an all-in-one React starter kit for high-performance e-commerce sites. You can clone, deploy, and fully customize with a few clicks.

And again, if you don’t have an account yet, go here and create one, you can sign up for free!

If you want to learn more about Next.js, don’t hesitate to go through the official documentation, it’s really good and useful.

Let’s go and get it done!

The first step is to login into Vercel and start a new project, then we just need to choose the Next.js Commerce template:

The Vercel templates

After we choose the Next.js Commerce template, we give the Git repo a name, and click on create:

Creating the starter kit Github repo

You can now go and check what Vercel has created for you in the Github repo:

Github

If you have experience developing Next.js apps, this repo would look familiar to you.

If you look at the readme file, you will see there is a demo site powered by Sitecore OrderCloud®!

Let’s get back and continue with our setup!

We have our Github repo, let’s skip the add integrations step for now and go straight to the deploy:

Build/deploy running for the first time…
The project got deployed to Vercel

Yas! your project got built and deployed to Vercel, you can now go and browse it (amazing isn’t it?)

The Commerce site is already up and running!

Setting up the Sitecore OrderCloud® integration

The site you’re browsing now already has some content, but as we are not integrating with any e-commerce platform yet, is just statically stored and generated. Let’s change that and switch our e-commerce solution to be powered by Sitecore OrderCloud®.

For doing that, go back to your Vercel project and then go to the Settings section, then click on Integrations and search for the OrderCloud by browsing the Marketplace

Browsing the integrations Marketplace

You would now see the Sitecore OrderCloud integration under the Commerce section:

SitecoreOrderCloud integration

Then click on Add Integration and choose your Personal Account as Vercel Scope. Click on continue and then select the project we just created for the OrderCloud integration.

Add the integration and then login to your Sitecore OrderCloud account.

In the next step, you’re prompted to choose your OrderCloud Marketplace. You would see that you can choose an existing one, but this time I want to create a new one “Seed new Marketplace (ID: “NEW”)

You can see the progress and logs, yeah Vercel is creating everything on OrderCloud for you!

Get back now to your Vercel project, settings and check the Environment Variables. You can see the key values created in the previous step:

Check your Sitecore OrderCloud® Marketplace

Now, login to Sitecore OrderCloud, go to Marketplaces and you should be now able to see the newly created “Vercel Commerce

Let’s try this out. Go to the API Console and then select “Catalogs“, click on send to make the API call, and check the results:

Copy the ID (solitary-storefront) so you can now browse categories by this Catalog ID:

Let’s browse the products now, copy the category ID (shirts) and make the request from the Products section:

Time to deploy it!

We just checked that the data is created on OrderCloud and we can easily query the API to get the results. Our Vercel integration is ready and now is time to deploy it so get our app consuming OrderCloud data.

just get back to your Vercel project, go to the deployments section, select the latest green one and redeploy it:

Uuuups! the build failed this time… That’s weird and unexpected, but let’s check logs and see what’s going on:

As I mentioned in the previous step, the OrderCloud integration created the environment variables to make the app communicate with OrderCloud.

Ok, that’s odd, it seems the “COMMERCE_PROVIDER” variable is not set properly. Let’s follow the logs recommendations and update it from “ordercloud” to “@vercel/commerce-ordercloud“. Save it and redeploy:

Yas! it seems to be good now, and the build is going good, you can also see in the logs how the site is being statically generated but making requests to the OrderCloud API this time:

You can see now our site getting data from OrderCloud!

Let’s make a quick update on OrderCloud and check changes in our storefront.

Let’s make an update on the Black Hat product. For that, go to the “Products” search for the “Black Hat” and then choose “PUT Create or update a product“. Change the price from 80 to 40, and the name to “OrderCloud Black Hat“:

We can query again to make sure the price got updated:

Get back to the site and check the updated product:

We have now our e-commerce solution deployed to Vercel, powered by Sitecore OrderCloud, and our Next.js app created on our Github repo.

In the next post, I’ll be exploring and sharing the local solution setup and the CI/CD so you can get an idea of how easy is to start building your solution with this tech stack.

I hope you found this post useful!

If you are interested in this topic, please don’t hesitate to watch the full demo example from Rob Earlam on YouTube.

Sitecore Moosend – Part III: Campaigns, Automation, Templates, Designer and Subscription Forms

In the previous posts (Part I and Part II) we’ve explored the Mailing Lists and Segmentation, Custom Fields, a bit about Automation and both the front end and API integration approaches.

Let’s go deeper into the other features and functionalities that Moosend provides out of the box and some quick examples on how to make use of those in your website.

Subscription Forms

Creating a form to, for example, get users subscribing to your newsletter is easy and straightforward. Just go to the Lead Generation section and then clikc on the Subscription Forms tab. Click on create new subscription form and you will see the different options Moosend proposes:

I’ll choose and create a Modal Pop-up, that will do the same than we have done in the previous posts via the API, adding a user to a mailing list with the birthday as optional field, so then we can apply our segmentation based on that.

After we choose a name and we go to the next step, you will see the option to make use of the designer.

The Designer

Moosend has a really cool and user friendly interface to build your email templates and forms. It already comes with a lot of different templates ready to be used making the user life’s easier. Also the editor, with drag & drop functionalities and grids helps to edit those or to create them from scratch.

We can then preview the form and then, if we’re good with it, use it.

In the editor, we go to the form settings and we assign our mailing list and also include the custom field (Date of Birth)

We enable all fields and keep only Email and Name as mandatory, the Date of Birth is optional.

Our form is ready, we clock on save and continue to get back to the Subscription Forms wizard.

In the “Visibility Settings” you will find a lot of different options to handle how and when to show up the modal in your webiste. You can also define and use rules for showing/hidding it.

The form is now ready to be published. Moosend offers different alternatives, like publishing straight to your configured site, embed a code or link to it.

After publishing, we can see and test our form, as you can see I’m just publishing it to my page:

I’ve subscribed two more users through the form (miguel@test4.com and miguel@test5.com). Let’s go and check how the mailing list looks now:

The new users have been added, please note the source is now = Form. If we check the segmentation, you will see that those users doesn’t belong to the “API Subscribers” as has been added though the newsletter form.

Campaigns

Let’s now create a campaign that we will use to put all things together, for doing that, we go to the Campaigns section and fill out the required data:

After we complete this section, we can assign this campaign to any of out Mailing Lists or Segments, for this example I’m assigning the “API Subscriber” segment from our list “My Testing List“.

The next step is to select an HTML or just text version, we will be using the HTML version for this example.

Same as when creating a Form, you can make use of the builtin templates or use de editor to edit it or start one from scratch.

We can now test the campaign, if we are good with it, we are then ready to enable and schedule it.

That’s very much it, we have now our campaign ready and sending emails to our segmentated mailing list.

If everything went well, you should receive a notification like this:

I hope you find this Moosend post series interesting and useful, it was just a quick and simplistic example just to give an overview on the different features and options but I hope you get the main idea and ways of working with Moosend, combining all those tools and featrures you can enrich your marketing and get it to the next level.

Thanks for reading and stay tuned for more Sitecore acquisition products overviews!

Sitecore Moosend – Part II: Mailing Lists, Custom Fields and API Integration

In my previous post I’ve shared a quick overview on Moosend and some of the main features. I advise you to take a look at the previous one before proceeding with this reading.

Today we will explore a bit more in depth the mailing lists, custom fields and also the API implementation approach.

Mailing Lists and Segments

In the previous post we created a Mailing List and added subscribers using the front end approach, applying Segmentation to it, we can improve the efficency of our marketing campaign by targeting the audience based on the data gathered from the users (custom fields) and the events recorded by Moosend.

Custom Fields

We can define in this section custom fields that we then can use for gathering data from the user, on top of the default ones (Name, Email and Mobile). We can use those afterwards for automation, segmentation, etc.

Let’s create a new custom field (Date of Birth) and make it optional:

Our custom field is now created and we can use it for our example. Check the generated tag: “recipient:Date of Birth“: you can make use of this token for pesonalize your campaigns.

Segments

Let’s for example take our previously created list “My Testing List” and create a new segmentation based on the Subscription Method = API Integration AND Date of Birth field < 01-01-2010“.

We give a name and then add a criteria, so here we’re creating a segmentation where we fetch “all contacts that subscribed through the API integration method and provided a Date of Birth before 01-01-2010“.

API Integration

As mentioned, this time we’ll be doing the integration it with the API approach. Moosend provides an API wrapper (Javascript or C# .NET) that makes working with it really straightforward, you can find the Nuget package here.

First of all, go to the setting section and then click in API key, copy it and save for later:

Now we can create our service class on .NET Core that will interact with the Moosend API:

MoosendService.cs

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Moosend.Api.Client.Common.Models;
using MyApp.WebApi.Configuration;

namespace MyApp.WebApi.Services
{
    public class MoosendService : IMoosendService
    {
        public MoosendService(IOptions<MoosendSettings> settings)
        {
            MoosendSettings = settings.Value;
        }

        private MoosendSettings MoosendSettings { get; }

        public async Task<Moosend.Api.Client.Common.Models.Subscriber> AddSubscriberAsync(string name, string email,
            DateTime dob)
        {
            var mailingListId = new Guid(MoosendSettings.MailingListID);
            var apiKey = new Guid(MoosendSettings.ApiKey);
            var apiClient = new Moosend.Api.Client.MoosendApiClient(apiKey);
            var customFields = new Dictionary<string, string> {{"Date of Birth", dob.ToLongDateString()}};
            var member = new SubscriberParams()
            {
                Email = email,
                Name = name,
                CustomFields = customFields
            };

            return await apiClient.SubscribeMemberAsync(mailingListId, member);
        }
    }
}

MoosendController.cs

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MyApp.WebApi.Services;

namespace MyApp.WebApi.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class MoosendController : ControllerBase
    {
        public MoosendController(IMoosendService moosendService)
        {
            MoosendService = moosendService;
        }

        private IMoosendService MoosendService { get; }

        [HttpPost("AddSubscriber/{name}/{email}/{dob}")]
        public async Task<Moosend.Api.Client.Common.Models.Subscriber> AddSubscriber(string name, string email,
            string dob)
        {
            return await MoosendService.AddSubscriberAsync(name, email, Convert.ToDateTime(dob));
        }
    }
}

Let’s now test it on Swaggwer, I’ll create 2 users with a birthdate before 01-01-2010 and one after this date, so we can test the segmentation properly:

Check now the Mailing List:

We can see our 3 members being added through the API, let’s take a look now at the segmentation:

We can see the two subscribers matching the segmentation criteria. In the next post I’ll be showing how to make use of the previously created mailing list, custom fields and segments with the campaigns and automation, we will also have a quick look at the template designer.

I hope you find it useful and keep tuned for more Moosend posts!

A first look at Moosend – One of the latest Sitecore acquisitions.

Moosend is a SaaS all-in-one email marketing tool that not only provides email marketing features but also advanced marketing automation, reporting, landing pages, tracking, newsletters, and subscription forms.

We can think about Moosend as the SaaS version of Sitecore’s Email Experience Manager (EXM) platform.

As this is one of the latest Sitecore acquisitions, in this post I’ll do a quick overview and first steps to get up to speed with it.

Moosend’s main features include:

  • API First Integration
  • Personalization, Segmentation and A/B Testing
  • Marketing Automation
  • Analytics and Reporting
  • Third Parties Integration
  • Landing Pages, Emails and Forms deigner with predefined templates

Dashboard

This is how the Moosend dashboard looks like:

First Steps

A cool thing about Moosend is that it allows you to create a free account, with already a lot of features to test. So, let’s go and create our first account.

Setting up the sender

Before starting to play with Moosend, we have to get our sender configured, for doing that, we go to the settings -> senders option and then “Add new sender”. We give a name (that will be used as the sender name while sending emails) and an email account.

The next step is to setup the DNS records (DKIM and SPF).

You would need to ask your IT department if you’re setting up your enterprise email account, for this demo I’m just setting up my personal server so I’ve access rights to do it myself.

If everything went good, then you should be able to verify the DNS records and get ready to start sending emails.

Configure your website

In order to enable the Moosend’s tracker on your website, go to settings -> websites -> Add website.

Enter the domain, and then you have several options to connect with it.

A website ID will be created, then you will have some connectors to use or just go with the custom installation that is quite a simple HTML code to be added to the head section of your layout.

After adding this snippet, your website can start making use of the tracker, meaning you can start easily sending events from the front end, for example for tracking, to trigger automation, or to subscribe a user to a mailing list.

Moosend gives two different approaches to facilitate the integration with your website, as I explained above, through the tracker or through calls to the API.

Let’s first have a quick look at the tracker.

You can identify the user by using the following event:

mootrack(‘identify’, ‘my.email@server.com’)

Then we can start, for example, to send a custom event that I will be using for triggering an automation.

Note: Moosend provides some examples on the website integration section: settings -> Websites -> MySite -> Action Tracking Configuration Examples.

Now, we are ready to play with some custom events, let’s go and see this in action by sending a “MyTestingAction” custom event to Moosend tracker, adding it for example, to a button on our site.

mootrack(‘MyTestingAction’);

Automation

Let’s now go to the Automations tab and create a new automation. You will see that Moosend provides a lot of different OOTB templates, but for this example, I’m just choosing the “Custom automation” option.

The Automations editor is really straightforward and easy to use.

Click on “Select your trigger” and you will see the different options, I selected for this case “When custom event is recorded”.

Then we select the options and we choose the event that we previously defined (MyTestingAction). Bear in mind that for the event to appear in the dropdown has to be fired at least once.

Then we add an action, in this case, I’m adding the user (email) to a mailing list (subscribe).

We can now add the action, I’ll be choosing the”Then subscribe to list” option, for the demo I’ve also created a Mailing List (“My Testing List”), and finally, you can choose to add him as verified or not.

Now the automation is ready, we can enable it and see it in action. The interface is really easy to use and the options are huge.

We check now that after triggering the custom event, the user is being added to the mailing list.

In the next post, I’ll explain how to create a campaign, a quick overview of the editor and the OOTB templates. We will be then adding an extra automation step to send an email to the user subscribed in the previous step. Also, I’ll be focusing and doing the demo with the API approach, I hope you find this interesting, and keep tuned for more Moosend related posts!