Saturday, March 1, 2025
Home Blog Page 2

Converging Worlds: Navigating The Blurring Lines Between Demand Gen & ABM 

0


As the marketing landscapes evolve, the once-clear distinctions between demand generation and account-based marketing (ABM) are fading. What was once a tactical separation —  with demand gen casting a wide net while ABM focused on personalized engagement — is now converging.  

Sarah Chen, VP of Marketing at a mid-sized B2B tech company, summed up the current marketing landscape perfectly: “It’s like being asked to play multiple instruments in an orchestra while also conducting and writing the music in real-time.” Her experience is far from unique.  

At the heart of this convergence lies a significant challenge: Resource allocation. Marketing teams are tasked with running broad, scalable campaigns while simultaneously delivering hyper-personalized experiences to key accounts. But balancing these efforts is easier said than done: In the 2024 Account-Based Marketing Benchmark Survey, 45% of practitioners said they encountered budget limitations and 44% highlighted internal resource shortages. 

A key insight from the report introduces the concept of the “Peanut Butter Effect” — spreading resources too thinly across demand gen and ABM initiatives. When teams attempt to prioritize both strategies without clear segmentation, the result is often diluted efforts that underperform on both fronts.  

Get the latest B2B Marketing News & Trends delivered directly to your inbox!

This challenge is particularly evident in mid-sized B2B tech companies, where marketing teams are tasked with generating demand at scale while nurturing high-value accounts. One marketing director described it as “running a marathon and a sprint at the same time,” a sentiment that reflects the struggle to balance competing priorities with limited bandwidth.  

Case Study: Collaboration As A Competitive Edge

One mid-sized technology company tackled this issue head-on by fostering stronger alignment between sales and marketing. Facing misaligned goals and wasted resources, the company implemented quarterly cross-functional workshops, unified KPIs and co-developed content strategies. The result was a 25% increase in marketing-qualified leads and more streamlined outreach for high-value accounts.  

This case exemplifies how integrated planning and shared goals can enhance efficiency, bridging the gap between demand gen and ABM without overextending resources. By breaking down silos, marketing teams can achieve greater ROI and ensure that broad and targeted strategies complement, rather than compete with, each other.  

Addressing Industry Gaps With Data & Technology

A critical barrier to effective convergence is the management of disparate data sets. Demand gen typically relies on lead-level data, while ABM needs account-level insights. This separation creates data silos, making it difficult for teams to measure success across both strategies.  

In response, 63% of ABM practitioners are investing in third-party data providers to enrich existing contacts, while 56% use data solutions to enhance account intelligence. AI-powered insights and unified data platforms are also becoming essential tools, allowing organizations to consolidate customer information into a single view that informs both broad and personalized campaigns.  

The ability to integrate and manage data across platforms is not just a technological advantage — it’s a strategic imperative. Companies that leverage comprehensive data insights report greater alignment between sales and marketing, ultimately driving more targeted engagement and increasing account retention.  

Novel Approaches To Balance Personalization & Scale

Achieving equilibrium between ABM and demand gen requires innovative approaches that prioritize flexibility. Key strategies include: 

Segmentation & Prioritization

Successful organizations segment high-value accounts for ABM while using demand gen to build broader awareness. This allows marketing teams to focus personalization efforts on fewer accounts without sacrificing top-of- funnel growth.  

Adaptive Budgeting

Rather than rigidly allocating budgets to either demand gen or ABM, leading companies adopt fluid budget models that shift based on real-time performance data. This ensures resources are directed to the highest-performing initiatives, optimizing ROI.  

Skill Diversification

Marketing teams are increasingly developing cross-functional skills, enabling them to shift between mass-market campaigns and personalized account outreach as needed. This reduces reliance on specialized teams and maximizes existing resources.  

Practical Takeaways For Marketers

For organizations looking to integrate demand gen and ABM, the following tips can provide a roadmap to success:  

1. Focus On High-Impact Account

Prioritize ABM efforts on the most valuable accounts while leveraging demand gen campaigns to attract new leads and fill the pipeline. 

2. Invest In Unified Tech Stacks

Consolidate tools and platforms to eliminate data silos and improve visibility across campaigns. Regular tech audits can help ensure tools are optimized and fully integrated. 

3. Promote Cross-Team Collaboration

Foster collaboration between sales and marketing to align strategies, share insights and refine lead generation processes.  

Embracing Convergence As An Opportunity

While the convergence of demand gen and ABM introduces complexity, it also presents an opportunity for marketers to rethink traditional strategies and adopt more holistic approaches. By aligning cross-functional teams, investing in data-driven insights and maintaining flexible resource allocation, organizations can drive greater efficiency and achieve sustained growth.  

In a rapidly evolving marketing environment, those who successfully navigate this convergence will not only meet current demands but position themselves as leaders in the future of B2B marketing. 


Jay Mellman is the SVP of Marketing for Business Online, a provider of digital B2B marketing services. He is a seasoned B2B and SaaS marketing leader who transforms complex technology into compelling market opportunities. Known for driving growth through strategic go-to-market initiatives and blending analytical thought with creative storytelling, Mellman builds high-performing teams and delivers measurable business impact across industries and products.  

 

 

Edmonton Real Estate Weekly Market Update Feb28/25

0


Listing information last updated on March 1st, 2025 at 1:47am CST.

Data is deemed reliable but is not guaranteed accurate by the REALTORS® Association Of Edmonton. Copyright 2025 by the REALTORS® Association Of Edmonton. All rights reserved.

Trademarks are owned or controlled by the Canadian Real Estate Association (CREA) and identify real estate professionals who are members of CREA (REALTOR®, REALTORS®) and/or the quality of services they provide (MLS®, Multiple Listing Service®).

Thermomix Margaritas – Create Bake Make

0


This easy Thermomix Margaritas recipe is perfect to enjoy on a warm evening with a friend! Made with just FIVE ingredients, this classic Lime Margarita recipe couldn’t be easier to put together.

Two Margaritas made using a thermomix in glasses garnished with salt and lime.Two Margaritas made using a thermomix in glasses garnished with salt and lime.

Although making Margaritas the conventional way is pretty straightforward, there is no denying that using your Thermomix to make delicious cocktails makes the process ever simpler!

These Margaritas take less than 5 minutes to prepare when using a Thermomix, and the most time consuming part really is juicing the lemons and garnishing the rim of your glass with salt!

You will also love the versatility of this recipe, with these Margaritas easily halved or doubled.

Overhead view of a margarita garnished with lime.Overhead view of a margarita garnished with lime.

Margarita Ingredients

Please note you will find the full list of ingredients and quantities in the recipe card below.

To make these delicious Margaritas, you will need: Tequila, Cointreau, Lime Juice, Sugar Syrup and Ice. If you don’t have Sugar Syrup you can substitute with Agave Syrup or even lemonade if you prefer. I do also recommend using fresh lime juice versus store bought.

If you would like to garnish the rims of your cocktails glasses (which I highly recommend!), you will also need approximately ¼ cup of salt and lime wedges.

Ingredients to make a margarita on a white bench.Ingredients to make a margarita on a white bench.

How to Make Margaritas

Please note you will find the full method in the recipe card below.

Making your own Margaritas really couldn’t be easier!

Step 1. If garnishing your glasses, place the salt on a small plate. Use a lime wedge and move around the rim of the glass before placing it into the salt. Set aside until needed.

Step 2. Place all of the Margarita ingredients into your Thermomix bowl and mix to combined.

Step 3. Divide the mixture between the two glasses and serve immediately.

Two Margaritas made using a thermomix in glasses garnished with salt and lime.Two Margaritas made using a thermomix in glasses garnished with salt and lime.

Recipe Hints and Tips

You can find sugar syrup at your local bottle shop (BWS, Dan Murphy’s etc) or you can also make your own. Alternatively, use Agave Syrup or even Lemonade.

Cointreau can be substituted with Grand Marnier or Triple Sec.

For best results, use fresh lime juice vs bottled juice to enhance the flavour.

You will need approximately 6 limes for this recipe, this includes extra for garnishing the glass.

These Thermomix Margaritas are best enjoyed immediately.

This recipe can also be made using a cocktail shaker instead of a Thermomix.

Frequently Asked Questions

What is the ratio when making Margaritas?

Traditionally the ratio used when making Margaritas is approximately 3 parts tequila, 2 parts orange liqueur and 1 part lime juice.

Can you make cocktails in a Thermomix?

Yes you sure can! You will find the full list of ingredients and recipe instructions to make Margaritas in a Thermomix in the recipe card below.

More Thermomix Cocktail Recipes

Looking for even more?

You can find even more delicious and easy Thermomix Cocktail recipes in our books and eBooks, shop the range here.

Image of the front covers of all 15 ThermoBliss Recipe Books.Image of the front covers of all 15 ThermoBliss Recipe Books.
Two Margaritas made using a thermomix in glasses garnished with salt and lime.Two Margaritas made using a thermomix in glasses garnished with salt and lime.

Thermomix Margaritas

This easy Thermomix Margaritas recipe is perfect to enjoy on a warm evening with a friend! Made with just FIVE ingredients, this classic Lime Margarita recipe couldn’t be easier to put together.

Prep Time 5 minutes

Total Time 5 minutes

Course Cocktails

Cuisine Modern

Servings 2 serves

Calories 244 kcal

Equipment

  • 2 x Cocktail Glasses

  • Thermomix

Instructions 

  • To garnish the cocktail glasses, slice a wedge of lime and rub around the rim of the glasses. Place the glasses rim down onto a plate covered with salt. Set aside until needed.

  • Place all of the Margarita ingredients into the Thermomix bowl. Mix for 15 seconds, speed 4 to combine and break up the ice. If you want the ice smaller, mix for a further 5 seconds, speed 5.

  • Divide the Margaritas between the two glasses and garnish with a wedge of lime. Serve immediately.

Notes

You can find sugar syrup at your local bottle shop (BWS, Dan Murphy’s etc) or you can also make your own. Alternatively, use Agave Syrup or even Lemonade.
Cointreau can be substituted with Grand Marnier or Triple Sec.
For best results, use fresh lime juice vs bottled juice to enhance the flavour.
You will need approximately 6 limes for this recipe, this includes extra for garnishing the glass.
These Thermomix Margaritas are best enjoyed immediately.
This recipe can also be made using a cocktail shaker instead of a Thermomix.

Nutrition

Calories: 244kcalCarbohydrates: 32gProtein: 0.5gFat: 0.2gSaturated Fat: 0.03gPolyunsaturated Fat: 0.1gMonounsaturated Fat: 0.01gSodium: 21mgPotassium: 115mgFiber: 1gSugar: 26gVitamin A: 42IUVitamin C: 25mgCalcium: 23mgIron: 1mg

Keyword Thermomix Margaritas



Recognition From Others – Blisters BBQ

0



Blisters BBQ is a restaurant that takes the art and craft of BBQ seriously. Our meat is hand prepped everyday and smoked all night to give our customers the best BBQ experience possible. The restaurant is located inside of Mother Hibbards gas station. We deliver (via Door Dash) and provide catering to people throughout Southeast Idaho.

Join The Statewide Celebration of Massachusetts Craft Beer

0


PRESS RELEASE / February 26, 2025 (Massachusetts) – Mass Beer Week is back from March 1-8, 2025, bringing together breweries, bars, restaurants, and retailers across the state to celebrate Massachusetts-made craft beer. The weeklong event features exclusive beer releases, tastings, live entertainment, brewery tours, and special events designed for craft beer enthusiasts and casual drinkers alike.

“Mass Beer Week is a time to showcase the incredible creativity and passion of our local breweries,” said Katie Stinchon, executive director at the Mass Brewers Guild. “Whether you’re a hophead, a lager lover, or just enjoy supporting local businesses, there’s something for everyone. Get out there and show local breweries some love.”

Highlights of Mass Beer Week 2025:

🔎 Find Events Near You: The official Mass Beer Week calendar is live at MassBeerWeek.org, where beer lovers can plan their week with tastings, tap takeovers, and more.

🏆 Brewery Passport Challenges: Visit all participating breweries in Central Mass, Marlborough/Hudson, or Somerville to be entered to win a grand prize filled with brewery merch and gift cards.

🍺 Limited-Edition Glassware: This year’s 16 oz Willi Becher glass, designed by local artist Meredith Price, will be available at participating breweries for just $6 while supplies last.

🎶 Live Music, Comedy & Entertainment: Breweries will host karaoke, open mics, live bands, and comedy showsthroughout the week, including Tracy Grammar at Floodwater Brewing and Comedy Night at Pioneer Valley Brewery.

🐷 Kicking Off on the Cape: Cape Cod Beer will offer guided brewery tours, while Barnstable Brewing is celebrating with a whole-hog roast featuring a special BBQ sauce made with their beer.

🔍 Behind-the-Scenes Brewery Tours: Take exclusive tours at Long Live Roxbury and Valley Malt to learn about the craft behind your favorite brews.

🎨 Get Crafty: Sip & sculpt pottery at Sam Adams Boston Taproom, create string art at Epigram Brew Co., or make a forest wreath at East Regiment Beer Company.

💜 Drink Beer, Give Back: Newburyport Brewing’s GIRL JAM will raise funds for Brigid’s House of Hope, supporting survivors of human trafficking.

🍽️ Food & Beer Pairings + Brewing History: Enjoy a four-course beer dinner at Moon Hill Brewing, or dive into brewing history with Dr. Terry Foster and Jeff Browning Sr. at Stone Path Malt.

🎉 Cheers to Brewery Anniversaries! Raise a glass to Gentile Brewing (9 years), Medusa Brewing Co. (10 years), Vanished Valley Brewing (5 years) and Break Rock (3 years).

Join the Celebration

Breweries, bars, restaurants, and retailers are encouraged to get involved by hosting events and adding them to the Mass Beer Week calendar. Simply host an event featuring Massachusetts made beer March 1-8, create a Facebook event and add @massbeerweek as a co-host.

For the full event lineup and more information, visit MassBeerWeek.org.

Issue 701

0



What does Dave write about when he has a fever? 🤒 Let’s find out!

Hanyou no Yashahime: Sengoku Otogizoushi Episode 5 Impression

0



Untitled112385.jpg

On this episode, a demon boy begins his bone collecting rampage. Later, Towa and her friends investigate the demon boy.

Wow, I’m starting to love Moroha more and more since the previous episode. She has a nice mixed personality from Inuyasha and Kagome themselves. Anyway, I find it hilarious that the demon boy plot is actually connected to Moroha. Also, it was awesome to see Myoga make an appearance and joins the girls just like the original series. Other than that, they revealed more connections between the girls and their parents. Now what’s going to happen next? I’ll be looking forward to it. Overall, cool demon boy plot and some more enjoyable scenes.

2025 Movement Grants AMA Highlights

0


On February 17, 2025, our team hosted a live Ask Me Anything (AMA) on the FAST Forum to answer questions about Movement Grants, our strategic grantmaking program dedicated to building and strengthening the animal advocacy movement. Below, we’ve rounded up some highlights. We hope these questions and answers provide deeper insight into our Movement Grants decision-making process and help you with your applications.

You can view the full AMA thread on the FAST Forum. Thank you to David van Beveren and the FAST Forum team for hosting this AMA.

Note: Questions and answers have been edited for length and/or clarity. Links to the original sources are provided beneath each response.


2025 Movement Grants

Do you accept grants for employee salaries?

Response: Yes, in some cases, we’ll fund operating costs like salaries, depending on the type and strength of the application and the operating budget of the organization where the employee works. —Elisabeth

(Source)

Do you fund projects from U.S. citizens who want to do outreach work in other countries?

We’ll fund projects from U.S. citizens who want to do outreach work in other countries; however, we take seriously the importance of our grantees understanding the cultural context of their work, so we’d need to see in the application some kind of evidence of the “right fit” for the person doing the work. For general outreach work, we’d also need to see evidence of a strategically developed approach that has the capacity to reach people at scale and track relevant outcomes. —Elisabeth

(Source)

Might ACE consider funding ballot initiative proposals that go further in their ask than the initiatives we saw in 2024?

We don’t have predetermined criteria for which ballot measures we would or wouldn’t fund, and proposals are assessed on a case-by-case basis. That said, three out of the four U.S. measures run in 2024 were unsuccessful, including the Denver fur ban, which we expected to perform better. Given that, we are more pessimistic that more radical measures can be achieved through ballot initiatives. We supported ProAnimal Future and Sentient Politics in part to capture insights from those campaigns, which will inform our future grantmaking. Beyond the ask, we also take into consideration the opposition to the measure, the political and media environment, and current public sentiment. —Holly and Eleanor

(Source)

What impact from ballot initiatives would ACE consider worthwhile? Are there specific metrics you hope to see campaigns use to measure their impact?

Perhaps it goes without saying that our ideal proposal is a campaign with a reasonable likelihood of success and a measure that would create a meaningful positive impact for animals. We also consider broader movement-building effects, such as engaging and training new advocates or shifting public attitudes toward animals. We would expect applicants to propose the most relevant impact metrics, particularly if they believe success should be measured beyond a campaign win. —Holly and Eleanor

(Source)

Are there other ways ACE may be interested in supporting ballot initiative campaigns that they may not choose to fund directly?

While we prioritize promoting the work of our recommended charities and grantees, we are open to hearing from other organizations that are doing high-impact work and/or have interesting learnings that could help others for our guest blog. For example, you can submit a guest blog proposal for writing about movement-level strategies, potentially impactful interventions, and discussions of interventions or strategies between experts from different angles. You can read more about what we publish on this page under “blog submission.” —Holly and Eleanor

(Source)

Does ACE fund academic research that aims to promote social change in meat consumption? If so, what kinds of costs are typically covered under Movement Grants, and what
criteria do you prioritize when evaluating research proposals?

We don’t fund academic research unless there is a clear dissemination plan that extends beyond publishing the work in academic journals. We want to understand how you’ll create information value that can be utilized by animal advocates and translate into a positive impact for animals. Therefore, without such a plan in place, we would be very reluctant to award funding. Additionally, academic research often has alternative sources of funding (e.g., government grants or other academic funders), so we prioritize supporting work that is unlikely to be funded by other means. —Elisabeth

(Source)

Do you consider funding to reach specific demographics (e.g., the Mexican-American community)?

Yes, we are open to projects focused on a particular demographic within a wider population, such as the Mexican-American community. In your application, we need to see how you plan to strategically target this population so that you are able to have an impact at scale. —Eleanor

(Source)

Would a storytelling-focused initiative (e.g., a short film designed to elevate the work of local advocates and campaigns) align with the priorities of ACE’s Movement Grants?

We would be open to receiving an Expression of Interest for such an initiative. Research on the impact of documentaries is mixed. While some films have had outsized effects, reported impact varies significantly by country and context. Because of this, our team is somewhat uncertain about documentaries as an intervention overall. A strong application would need to clearly demonstrate how the film and its distribution would lead to meaningful outcomes for animals.

We’d be particularly interested in how such a project would go beyond raising awareness to create measurable outcomes, whether through policy change, movement-building, or direct improvements for animals. If you decide to apply, outlining a clear theory of change and providing examples of how similar initiatives have led to measurable outcomes would strengthen your application. —Eleanor

(Source)

Would you consider funding individuals (who have a fiscal sponsor) to do capacity-building work for the movement?

Yes, capacity-building work is within the scope of the program. You can find the full Movement Grants eligibility criteria here on our website under the FAQs: What are we interested in funding? What are we not interested in funding? —Eleanor

(Source)

What criteria does ACE look for in event-focused proposals?

We would need to understand how the event would meaningfully change the lives of many animals. Specifically, we’d be interested in whether the event targets influential individuals within the movement, how it differs from or complements existing initiatives, and what concrete outcomes it aims to achieve.

If you decide to submit an expression of interest, providing specific examples of expected outcomes would strengthen your proposal. —Eleanor

(Source)

Are you eager to fund federal legislation, corporate policy change, governmental policy change, and/or effective digital campaigns to help upend the Ultra Processed Food myth?

Federal legislation, corporate policy change, and governmental policy change all have the potential to have a huge impact based on the change that is being called for and the likelihood of success. For each avenue, we would like to hear what your expected outcomes are, how you’re tracking them, and how you expect those outcomes to have downstream impacts for animals. We are currently highly uncertain about the impact of digital campaigns, but we find that they can be impactful as part of a wider campaign utilizing multiple tactics. —Elisabeth

(Source)

Do you fund organizations that rescue and rehabilitate farmed and wild animals, provide humane education with a focus on veganism, and advocate for policy changes to benefit
animals?

ACE doesn’t currently prioritize organizations and projects working in direct animal care (rescue and rehabilitation) as we focus on larger-scale advocacy work. For example, see our recent grant recipients. However, we would be open to hearing more about your education work (if it is directed toward a large number of people) or your work advocating for policy change. We ideally want to see work that is scalable and has the potential to affect a large number of animals. —Holly

(Source)

What are some trends in the funding space that applicants might not be aware of?

One exciting trend is the increase in climate funders supporting a reduction in animal agriculture through dietary change and alternative proteins as climate mitigation. Just last week, the Bezos Centre for Sustainable Protein opened at Imperial College London with $30M in funding. This shift could open up a lot of funding opportunities for organizations that are currently solely reliant on funding from funders concerned with animal welfare. —Eleanor

(Source)

What do you enjoy when it comes to reading and assessing funding applications?

I enjoy reading applications from new organizations the most—that’s not to say they are more/less likely to get funding—but it is such a pleasure to see the dedication and bravery it takes to start something new. Even more so when I see them working in a country where there is a nascent animal advocacy movement. —Eleanor

(Source)

What’s one thing you wished applicants would do less or more?

I would like to see some applicants include a bit more detail on the context in which they are working, in particular, whether there are political, social, or economic factors that might impact their work. Similarly, for some niche species-specific work, it is useful for our grant review team if you include the animal science research you are relying on. —Eleanor

(Source)

Do you offer matching grants?

Response: ACE does not offer matching grants in the sense that we do not require grantees to secure additional funding as a condition of our grants. However, if an organization has received a grant from another funder that requires matching funds, an ACE grant can be used to fulfill that requirement—unless the other funder has specific restrictions that prevent this. —Eleanor

(Source)

When will Movement Grants start?

This year, we will have two funding rounds. The first round of grants will likely be disbursed in May and June, and the second round will likely be disbursed in December and January. —Eleanor

(Source)

Should applicants specify the activities they plan to pursue with this grant, or is it better to discuss the activities completed in recent years?

If you decide to complete an Expression of Interest, please focus on what you intend to use the grant funds for. If you are invited to complete a full application, there will be a question about your achievements in previous years where you can outline your recent accomplishments. You can also learn more in this video. —Eleanor

(Source)

What types of projects are most likely to receive funding in this grant round?

Since our process is application-based, it’s difficult to predict exactly which projects will be funded—it depends on the proposals we receive. Our portfolio this round is likely to look similar to the previous round. There are also a few areas where we would like to have seen more applications last round. In particular, we’d like to see more proposals focused on support for egg-laying hens, given the strong track record of corporate welfare campaigns in many different countries. We also didn’t fund any entirely wild animal-focused projects last round, and we’d like to see more applications from Southeast Asia, which remains significantly underfunded. —Eleanor

(Source)

What are the key qualities of a strong Expression of Interest (EOI)?

EOIs should be short and to the point—they are much less detailed than the application. A strong EOI clearly describes the planned activities, target groups, animal populations being helped, and how the intervention creates impact. We should be able to quickly understand the scale of the project and its potential effects. —Eleanor

(Source)

What common mistakes should applicants avoid?

Common mistakes include:

  • Applicants misinterpreting questions or not answering as we would have expected them to. Most questions have an (i) icon next to it with additional guidance on what we’re looking for.
  • Attaching or linking to extra documents instead of properly answering application questions.
  • Insufficient desk research; in particular, new organizations sometimes miss key risks because they haven’t fully explored the context or intervention.
  • Improper use of AI; in particular, some applicants generate entire sections with AI without checking for accuracy or relevance. We find that AI-generated plans and budgets usually don’t make sense, and this resulted in a number of rejected applications last round. —Eleanor

(Source)

How does ACE measure the effectiveness of funded projects?

We assess effectiveness on a case-by-case basis, depending on the intervention and the stage of the project (e.g., pilot, scaling, or full implementation). We start with what the applicant states they aim to achieve and how they plan to measure it. Based on this, we identify additional reporting requirements and share them with the grant recipient early on in the grant period, allowing them to provide feedback if they believe other metrics would be more useful. We are in the early stages of implementing our own Measurement, Evaluation, and Learning (MEL) in the Movement Grants program, which will include what we learn from our grant reporting to understand our own impact. We hope to share how this is going toward the end of the year. —Eleanor

(Source)

What is the average or maximum grant amount awarded?

We don’t have a strict cap on grant amounts, but we expect funding sizes to be in line with previous rounds. Last year, the average grant size was $37,397 USD, including a Movement Grant recommendation that ACE did not disburse. —Eleanor

(Source)

Do you accept proposals that incorporate regranting to other relevant actors in the movement?

At this time, we are not considering applications for regranting, as we are a regranting organization ourselves. However, if you know of a regranter playing an important role in the movement, we’d be happy to hear about them—we may be able to share their information within our network. —Eleanor

(Source)

What are the most impactful areas for projects in Africa (especially sub-Saharan Africa)?

Sub-Saharan Africa encompasses many countries and contexts, so I am reluctant to make any sweeping statements about the most impactful areas for such a large region. However, I will try to offer some useful thoughts.

There has been relatively little advocacy work in the region. If I were to advise groups on what they might focus on, I would start by looking at what interventions have been the most impactful in other parts of the world, and focus on how one might adapt such approaches to this context. For example, higher rates of informal markets or different communication norms could lead to significant changes in how you implement an intervention that has been successful in other parts of the world.

Another approach is to examine the interventions that have specifically succeeded in your country for other (non-animal) issues and consider whether these interventions could be adapted to benefit animals.

The current and predicted rates of animal farming and consumption vary greatly between countries within sub-Saharan Africa, so it is possible that if you have the freedom to move and work in different countries (I appreciate that many don’t have this privilege), you may find that you can have a greater impact in your work.

We are not experts in advocacy in this region, so I would love to see what others think in the replies! —Eleanor

(Source)

If you’d like to support highly promising projects working to reduce animal suffering around the world, make a gift to our Movement Grants today.

Foundry releases Nuke 16.0 | CG Channel

0


Originally posted on 12 December 2024 for the beta, and updated for the final release.

Foundry has released Nuke 16.0, the latest update to its family of compositing apps.

The update lays the foundations of a new native multishot compositing workflow, updates Nuke’s 3D compositing system, and improves interactive performance when rotoscoping.

NukeX, the advanced edition, also gets workflow improvements to the BlinkScript editor.

Nuke Studio, which includes editorial capabilities, gets a new contact sheet view, support for multi-channel soft effects, and a new quick export system.

A parallel release, Nuke 15.2, provides some of the same features, but remains on the VFX Reference Platform CY2023 spec, rather than updating to CY2024.

Nuke 16.0, NukeX 16.0, Nuke Studio 16.0: New native multishot workflow
Nuke 16.0 is Foundry’s first serious step towards implementing support for a native multishot compositing workflow inside the software.

Whereas Nuke was designed for use on individual shots, with a one-to-one relationship between a shot and a Nuke .nk script, Foundry now aims to let artists reuse scripts across shots.

The “backbone” of the system is Graph Scope Variables (GSVs), which make it possible to define the data required for multiple contexts and scopes in a single Nuke script, while Group nodes define the nature of those ‘scopes’, and make it possible to inherit and override variables.

The release introduces many of the day-to-day features needed for working with GSVs and Group nodes, including a new VariableGroup node, for defining variables or scopes, and a VariableSwitch node, for switching between different shots or scopes using those variables.

A new Variables Panel lets artists interact with the available variables within a script, and a Group View lets them edit the contents of multiple Group nodes without having to switch tabs.

GSVs are also now supported in LiveGroups, and when rendering from the command line, making it possible to render scripts in the correct shot context.

Some of the functionality was actually introduced in Nuke 15.1, but the UI for the new features was hidden by default.

Nuke 16.0, NukeX 16.0, Nuke Studio 16.0: Link Nodes
Workflow improvements to Nuke’s node graph include Link Nodes, a new node type that makes it possible to create a linked copy of a node.

Change made to one node are then automatically propagated to the other, with users still able to manually override any of the knobs.

Nuke 16.0, NukeX 16.0, Nuke Studio 16.0: Updates to the 3D system and ScanlineRender
The USD-based 3D compositing system introduced two years ago in Nuke 14.0 gets an update, although it remains in beta.

While there are a couple of new nodes, a key objective is simply to update the most commonly used nodes – including GeoCard, GeoTransform, GeoMerge and GeoScene – based on user feedback.

Foundry has also “started the building blocks for ray tracing”, with ScanlineRender2, the new version of the ScanlineRender render node, being a “ray traced architecture by default”, although shader support for lights and materials is still not fully implemented.

The functionality is aimed at compositors – particularly for generating accurate render passes late in production – and “shouldn’t be thought of as a replacement to large-scale scene renders”.

Nuke 16.0, NukeX 16.0, Nuke Studio 16.0: Better roto performance
Under the hood, the release also features a number of changes intended to improve performance when rotoscoping, particularly when using large numbers of roto shapes, or when working with motion blur.

The changes are intended to reduce UI lag, and to raise the frame rates achieved when playing back complex shots to levels sufficient to resolve edge issues like boiling.

NukeX 16.0, Nuke Studio 16.0: Quality-of-life improvements to BlinkScript
TDs get quality-of-life improvements to the BlinkScript editor, Nuke’s native scripting system, which has been updated to support “common IDE functionality”.

That includes ‘text and type’ behaviours like auto-indenting and bracket autoclosure; find and replace; and a Tab menu with autofill suggestions and context-specific documentation.

Library Files enable users to share common functions and code snippets across multiple kernels and projects.

A new ‘Safety Rails‘ system makes it easier to catch problems when prototyping new BlinkScripts and makes the consequences “less dramatic” when mistakes occur.

Nuke Studio 16.0: New Contact Sheet, Multichannel Soft Effects and quick export system
New features in Nuke Studio include the Contact Sheet view.

It is makes it easier to compare multiple shots, and supports user-defined rules for the order in which the contact sheet is populated with shots, and tag filtering of shots.

The Soft Effects system gets support for multichannel effects, with users now able to view and modify multilayer EXR files within the timeline.

Potential uses include masking color effects with non-RGBA layers like mattes or depth passes.

Support for layer transforms in the timeline is intended to reduce the need for slap comps, and to enable supervisors to provide more accurate feedback when creating sample frames.

In addition, a new render engine based on Nuke Studio’s real-time playback engine speeds up exports of sequences as ProRes, DNxHD, DNxHR and H.264 videos.

It provides an “average 12-fold increase in performance” over the existing export system.

VFX Reference Platform support and changes to pipeline integration
Nuke 16.0 also moves the software to support the VFX Reference Platform CY2024 spec.

A parallel release, Nuke 15.2, is intended for studios who don’t want to update their pipelines from the CY2023 spec, and has some of the same features, including multi-shot compositing,

Both releases switch Nuke from Apple’s system OpenGL library to Foundry’s own alternative, FoundryGL, when running on macOS, Apple having deprecated OpenGL in macOS 10.14.

Price and system requirements
Nuke 16.0 is compatible with Windows 10+, Rocky Linux 9.0 and macOS 14.0+. The software is rental-only.

Annual subscriptions cost $3,649/year for Nuke, up $180/year since the release of Nuke 15.0; $4,969/year for NukeX, up $240/year; and $6,069/year for Nuke Studio, up $290/year.

Nuke Render licenses cost $440/year, up $21/year.

Subscriptions to Nuke Indie, the feature- and resolution-limited commercial edition for artists earning under $100,000/year, cost $499/year.

Read an overview of the features in Nuke 16.0 on Foundry’s website

Read a full list of new features in Nuke 16.0 in the online release notes

Have your say on this story by following CG Channel on Facebook, Instagram and X (formerly Twitter). As well as being able to comment on stories, followers of our social media accounts can see videos we don’t post on the site itself, including making-ofs for the latest VFX movies, animations, games cinematics and motion graphics projects.



Track Users Who Are Offline In Google Analytics

0


The steady increase in mobile use over the last years has introduced some new challenges for web analytics. It’s not just about mismatches in the tracking model (the concept of sessions is even more absurd for apps than it is for desktop browsing), but about something more fundamental, more basic. Think about it: if a visitor visits the website using a mobile device, there’s a significant chance of them losing internet connectivity and going unintentionally offline.

Actually, it’s enough for them to simply traverse an area with poor coverage – if the HTTP requests sent by the browser don’t complete in time, they timeout, and the hits are lost.

For Google Analytics pageviews it’s not such a big deal, because if the user sees the web page, it’s very likely the first pageview has completed. However, what about all the other interactions that we want to track, and the user doesn’t have an internet connection to boot? That’s right – we’ll lose these interactions, since the requests are dropped by the browser and never picked up, even when the user gets their connection back.

In this article, the brilliant David Vallejo and I will offer a solution for retrieving these hits initially dropped by the browser due to the internet connection being offline. OK, who am I kidding, this is all David. I’m just a glorified editor at this point.

Anyway, let’s frame it like this: the visitor is viewing our contact page, and we have an event queued up for when they click on our email contact information. However, the visitor is also on the subway, and the moment they click the email, they enter a tunnel. Oh noes! They lose their internet connection (damn subways without WiFi), and we miss our vital conversion tracking.

That’s the premise. Here’s the execution.

In this article, we’ll touch upon a number of fairly technical concepts, but we’ll try to frame them so that they make sense in the big picture.

  1. Universal Analytics Tasks API

  2. The browser’s Storage API

  3. Sending Google Analytics hits with a delay (the &qt parameter)

  4. Sending custom POST and HEAD requests (HTTP protocol)

  5. Batching Universal Analytics Hits

All of these concepts are very useful to know if you want to know more about the mechanisms that the web browser employs to compile and dispatch requests to Universal Analytics.

Let’s go!


X


The Simmer Newsletter

Subscribe to the Simmer newsletter to get the latest news and content from Simo Ahava into your email inbox!

1. Universal Analytics Tasks API

Each time a send command is dispatched to the ga() global method, a series of tasks are run in sequence by the analytics.js library. These tasks do a number of things, such as construct the payload, validate it, sample the requests, and finally dispatch the requests to the Universal Analytics endpoint.

The neat thing about these tasks is that we can intercept them and modify them using the API provided by analytics.js.

You can find a list of all available tasks in the API here. However, in this article we will focus on just a very special, very significant task: customTask. It’s a new task introduced very recently (here’s a guide by Simo).

This task is true to its name – it’s entirely customizable. It runs first in the task queue, so you can use it to configure the tracker object or even to set other tasks up for customization.

In this guide, we’ll use customTask to modify the sendHitTask. This way we can check if the user has internet connectivity when sendHitTask is run, and we can do a number of things if the user has dropped their connection. We use customTask instead of directly accessing sendHitTask simply because this way is much more Google Tag Manager-friendly.

In short, here’s the process:

customTask modifies sendHitTask with OUR CODE before hit is sent.

In order to detect if the user has internet connectivity, we could simply poll our own web server endpoint. However, that wouldn’t be a good litmus test since it could be just Google’s servers that are not responding. That’s why we’ll actually poll Google’s endpoint to check if the user has the connectivity required for Google Analytics tracking.

2. The offline tracker

The solution is that with every single request to Universal Analytics, we’ll send an HTTP HEAD request to the Universal Analytics endpoint. If the endpoint isn’t responding, we can infer that the user does not have connectivity for communicating with Google Analytics, and so we’ll store the hit into browser storage until such a time that internet coverage is restored.

We’ll use localStorage for the queue, but we’ll need to cheat a little. localStorage itself doesn’t introduce any structure or a deeper data model – it just processes key-value pairs. So, to give us some additional flexibility, we’ll use the Lockr open-source database layer. It’s a simple and efficient framework, and it has pretty solid browser support.

This solution picks up the Universal Analytics hit payload from sendHitTask, and if there is no internet connection, this hit is stored in localStorage with the timestamp of the request. Thus, when we later do manage to send the stored hit, we can send it at its original timestamp to Universal Analytics.

2.1. The &qt parameter

The &qt Measurement Protocol stands for queue time. Basically, you can set a number in milliseconds in that parameter, and the hit will be sent with a timestamp that many milliseconds in the past. For example, if I know that the hit I want to send actually happened 45 minutes ago, I can set the parameter to:

&qt=2700000

There’s just an odd little quirk you need to know about &qt. The latest you can send the displaced hit is at 03:59:59 the following day (in the timezone of the Google Analytics view the hit is being sent to). Thus, the maximum value for &qt is 27 hours, 59 minutes, and 59 seconds (in milliseconds), if the hit occurred at exactly midnight, and you then send it the following morning, just before 4 AM.

Yes, it might be difficult to grasp, so we’ll go with the official recommendation: avoid sending hits more than 4 hours in the past, since there’s no guarantee they will get sent.

3. The HTTP HEAD request

So what is this HEAD request and why are we using it? Well, it’s identical to GET, except it only returns the HTTP headers (and associated metadata), never any content.

It’s thus a great method to use if we only want to test an endpoint, and not get into the expensive process of actually retrieving data from it.

Since we are only interested in knowing if the Universal Analytics endpoint responds, the HTTP HEAD request is perfect for this purpose. Also, see how efficient it is compared to POST and GET:

4. The JavaScript code

The code comes in three parts. First is the library for extending the database: Lockr. Next we have the customTask execution, and finally we’ll chain the HTTP HEAD and batch requests together to make the whole thing click.

4.1. Lockr download

To get started, go ahead and load Lockr on your site in any way you want. If you’re using Google Tag Manager, we recommend loading the following code in a Custom HTML Tag that fires on All Pages with the highest possible Tag Priority. Alternatively, if you accept some overhead and redundancy, you can just add the library to the top of the Custom JavaScript Variable itself, as in the example in the next chapter.

Here’s the minified JavaScript code  – it should be executed by the browser before the offline tracking solution is run:

!function(e,t){"undefined"!=typeof exports?"undefined"!=typeof module&&module.exports&&(exports=module.exports=t(e,exports)):"function"==typeof define&&define.amd?define(["exports"],function(r){e.Lockr=t(e,r)}):e.Lockr=t(e,{})}(this,function(e,t){"use strict";return Array.prototype.indexOf||(Array.prototype.indexOf=function(e){var t=this.length>>>0,r=Number(arguments[1])||0;for((r=r<0?Math.ceil(r):Math.floor(r))<0&&(r+=t);rif(r in this&&this[r]===e)return r;return-1}),t.prefix="",t._getPrefixedKey=function(e,t){return(t=t||{}).noPrefix?e:this.prefix+e},t.set=function(e,t,r){var o=this._getPrefixedKey(e,r);try{localStorage.setItem(o,JSON.stringify({data:t}))}catch(r){console&&console.warn("Lockr didn't successfully save the '{"+e+": "+t+"}' pair, because the localStorage is full.")}},t.get=function(e,t,r){var o,n=this._getPrefixedKey(e,r);try{o=JSON.parse(localStorage.getItem(n))}catch(e){o=localStorage[n]?{data:localStorage.getItem(n)}:null}return o?"object"==typeof o&&void 0!==o.data?o.data:void 0:t},t.sadd=function(e,r,o){var n,a=this._getPrefixedKey(e,o),i=t.smembers(e);if(i.indexOf(r)>-1)return null;try{i.push(r),n=JSON.stringify({data:i}),localStorage.setItem(a,n)}catch(t){console.log(t),console&&console.warn("Lockr didn't successfully add the "+r+" to "+e+" set, because the localStorage is full.")}},t.smembers=function(e,t){var r,o=this._getPrefixedKey(e,t);try{r=JSON.parse(localStorage.getItem(o))}catch(e){r=null}return r&&r.data?r.data:[]},t.sismember=function(e,r,o){return t.smembers(e).indexOf(r)>-1},t.keys=function(){var e=[],r=Object.keys(localStorage);return 0===t.prefix.length?r:(r.forEach(function(r){-1!==r.indexOf(t.prefix)&&e.push(r.replace(t.prefix,""))}),e)},t.getAll=function(e){var r=t.keys();return e?r.reduce(function(e,r){var o={};return o[r]=t.get(r),e.push(o),e},[]):r.map(function(e){return t.get(e)})},t.srem=function(e,r,o){var n,a,i=this._getPrefixedKey(e,o),c=t.smembers(e,r);(a=c.indexOf(r))>-1&&c.splice(a,1),n=JSON.stringify({data:c});try{localStorage.setItem(i,n)}catch(t){console&&console.warn("Lockr couldn't remove the "+r+" from the set "+e)}},t.rm=function(e){var t=this._getPrefixedKey(e);localStorage.removeItem(t)},t.flush=function(){t.prefix.length?t.keys().forEach(function(e){localStorage.removeItem(t._getPrefixedKey(e))}):localStorage.clear()},t});

After this code puke, we’re ready to jump in the deep end with some offline hit tracking!

4.2. Offline hit tracker for on-page Universal Analytics

The following JavaScript runs with the default Universal Analytics tracker, and thus any hits sent with the ga('send', '...'); will be included in the process.

To make the whole thing work, you should setup your code in the following order:

<head>
  ...
  <script>
    // Put the Lockr code here first
  script>
  <script>
    var _offlineTracker = function(customTaskModel) {
      // _offlineTracker (see below) here
    };
  script>
  <script>
    // Universal Analytics snippet here
    ga('create', 'UA-12345-1');
    // Add the following line AFTER the 'create' command and BEFORE the first 'send' command
    ga('set', 'customTask', _offlineTracker);
    ga('send', 'pageview');
  script>
  ...
head>

And here’s the code for the _offlineTracker callback function.

var _offlineTracker = function(customTaskModel) {

  Lockr.prefix = 'ga_';
  // Grab the original sentHitTask Function from the first tracker. to kept the original hit sending function.
  var originalSendHitTask = customTaskModel.get('sendHitTask');
  customTaskModel.set('sendHitTask', function(model) {
    // Let's send the original hit using the native functionality
    originalSendHitTask(model);
    // Grab the hit Payload
    var payload_lz = model.get('hitPayload');
    // Check if GA Endpoint is Ready
    var http = new XMLHttpRequest();
    http.open('HEAD', 'https://www.google-analytics.com/collect');
    http.onreadystatechange = function() {
      // Google Analytics endpoint is not reachable, let's save the hit                
      if (this.readyState === this.DONE && this.status !== 200) {
        Lockr.sadd('hits', payload_lz + "&qt=" + (new Date() * 1));
      } else {
        // Google Analytics endpoint is available, let's check if there are any unsent hits
        if (Lockr.smembers("hits").length > 0) {                        
          // Process hits in queue
          var current_ts = new Date() * 1 / 1000;
          var hits = Lockr.smembers("hits");

          // ./batch endpoint only allows 20 hits per batch, let's chunk the hits array. 
          var chunk_size = 20;
          var chunked_hits = Lockr.smembers("hits").map(function(e, i) {
            return i % chunk_size === 0 ? hits.slice(i, i + chunk_size) : null;
          }).filter(function(e) {
            return e;
          });
          // Let's loop thru the chunks array and send the hits to GA
          for (var i = 0; i < chunked_hits.length; i++) {
            var xhr = new XMLHttpRequest();
            xhr.open('POST', 'https://www.google-analytics.com/batch', true);
            // Build the Batch Payload and Take care of calculating the Queue Time 
            xhr.send(chunked_hits[i].map(function(x) {
              if (x.indexOf("&qt=") > -1) {
                return x.replace(/qt=([^&]*)/, "qt=" + Math.round(current_ts - x.match(/qt=([^&]*)/)[1] / 1000) * 1000);
              } else return x;
            }).join("\n"));
          }
          //Hits sent, flush the Storage
          Lockr.flush();
        }
      }
    };
    http.send();
  });
};

Once you create this _offlineTracker and invoke it in the ga('set', 'customTask', _offlineTracker) command, every single hit that uses this tracker will be stored in the queue if there is no internet connectivity. Once a hit is sent with a solid connection, all hits in the queue are sent as well.

4.3. Offline hit tracker for Google Tag Manager

With Google Tag Manager, you can get by with a single Custom JavaScript variable. This variable can be configured to include the Lockr code as well, so it’s completely self-contained. Give the variable a descriptive name, e.g. {{JS – customTask Offline Hit Tracker}} and put the following code within:

function() {
  return function(customTaskModel) {
    // Load Lockr if it hasn't already been loaded
    if (!window.Lockr) {
      !function(e,t){"undefined"!=typeof exports?"undefined"!=typeof module&&module.exports&&(exports=module.exports=t(e,exports)):"function"==typeof define&&define.amd?define(["exports"],function(r){e.Lockr=t(e,r)}):e.Lockr=t(e,{})}(this,function(e,t){"use strict";return Array.prototype.indexOf||(Array.prototype.indexOf=function(e){var t=this.length>>>0,r=Number(arguments[1])||0;for((r=r<0?Math.ceil(r):Math.floor(r))<0&&(r+=t);rif(r in this&&this[r]===e)return r;return-1}),t.prefix="",t._getPrefixedKey=function(e,t){return(t=t||{}).noPrefix?e:this.prefix+e},t.set=function(e,t,r){var o=this._getPrefixedKey(e,r);try{localStorage.setItem(o,JSON.stringify({data:t}))}catch(r){console&&console.warn("Lockr didn't successfully save the '{"+e+": "+t+"}' pair, because the localStorage is full.")}},t.get=function(e,t,r){var o,n=this._getPrefixedKey(e,r);try{o=JSON.parse(localStorage.getItem(n))}catch(e){o=localStorage[n]?{data:localStorage.getItem(n)}:null}return o?"object"==typeof o&&void 0!==o.data?o.data:void 0:t},t.sadd=function(e,r,o){var n,a=this._getPrefixedKey(e,o),i=t.smembers(e);if(i.indexOf(r)>-1)return null;try{i.push(r),n=JSON.stringify({data:i}),localStorage.setItem(a,n)}catch(t){console.log(t),console&&console.warn("Lockr didn't successfully add the "+r+" to "+e+" set, because the localStorage is full.")}},t.smembers=function(e,t){var r,o=this._getPrefixedKey(e,t);try{r=JSON.parse(localStorage.getItem(o))}catch(e){r=null}return r&&r.data?r.data:[]},t.sismember=function(e,r,o){return t.smembers(e).indexOf(r)>-1},t.keys=function(){var e=[],r=Object.keys(localStorage);return 0===t.prefix.length?r:(r.forEach(function(r){-1!==r.indexOf(t.prefix)&&e.push(r.replace(t.prefix,""))}),e)},t.getAll=function(e){var r=t.keys();return e?r.reduce(function(e,r){var o={};return o[r]=t.get(r),e.push(o),e},[]):r.map(function(e){return t.get(e)})},t.srem=function(e,r,o){var n,a,i=this._getPrefixedKey(e,o),c=t.smembers(e,r);(a=c.indexOf(r))>-1&&c.splice(a,1),n=JSON.stringify({data:c});try{localStorage.setItem(i,n)}catch(t){console&&console.warn("Lockr couldn't remove the "+r+" from the set "+e)}},t.rm=function(e){var t=this._getPrefixedKey(e);localStorage.removeItem(t)},t.flush=function(){t.prefix.length?t.keys().forEach(function(e){localStorage.removeItem(t._getPrefixedKey(e))}):localStorage.clear()},t});
    }
    Lockr.prefix = 'ga_';
    // Grab the original sentHitTask Function from the first tracker. to kept the original hit sending function.
    var originalSendHitTask = customTaskModel.get('sendHitTask');
    customTaskModel.set('sendHitTask', function(model) {
      // Let's send the original hit using the native functionality
      originalSendHitTask(model);
      // Grab the hit Payload
      var payload_lz = model.get('hitPayload');
      // Check if GA Endpoint is Ready
      var http = new XMLHttpRequest();
      http.open('HEAD', 'https://www.google-analytics.com/collect');
      http.onreadystatechange = function() {
        // Google Analytics endpoint is not reachable, let's save the hit                
        if (this.readyState === this.DONE && this.status !== 200) {
          Lockr.sadd('hits', payload_lz + "&qt=" + (new Date() * 1));
        } else {
          // Google Analytics endpoint is available, let's check if there are any unsent hits
          if (Lockr.smembers("hits").length > 0) {                        
            // Process hits in queue
            var current_ts = new Date() * 1 / 1000;
            var hits = Lockr.smembers("hits");

            // ./batch endpoint only allows 20 hits per batch, let's chunk the hits array. 
            var chunk_size = 20;
            var chunked_hits = Lockr.smembers("hits").map(function(e, i) {
              return i % chunk_size === 0 ? hits.slice(i, i + chunk_size) : null;
            }).filter(function(e) {
              return e;
            });
            // Let's loop thru the chunks array and send the hits to GA
            for (var i = 0; i < chunked_hits.length; i++) {
              var xhr = new XMLHttpRequest();
              xhr.open('POST', 'https://www.google-analytics.com/batch', true);
              // Build the Batch Payload and Take care of calculating the Queue Time 
              xhr.send(chunked_hits[i].map(function(x) {
                if (x.indexOf("&qt=") > -1) {
                  return x.replace(/qt=([^&]*)/, "qt=" + Math.round(current_ts - x.match(/qt=([^&]*)/)[1] / 1000) * 1000);
                } else return x;
              }).join("\n"));
            }
            //Hits sent, flush the Storage
            Lockr.flush();
          }
        }
      };
      http.send();
    });
  };
}

Add this code to all your Universal Analytics tags by scrolling to More settings -> Fields to set. Here you add a new field with:

Field name: customTask
Value: {{JS – customTask Offline Hit Tracker}}

Once you’ve done this, then all your tags with this customTask setting are protected against poor connectivity, and whenever the connection is restored, the batch queue is processed.

4.4. About batching

Universal Analytics lets you send hits to its endpoint in batches. This is used mostly by the iOS and Android SDKs. The main point in using the batch endpoint (/batch) is to have as few HTTP requests dispatched as possible. Here, batching means that we can send multiple Universal Analytics payloads in a single HTTP request.

Batching does have some limitations we’ll need to consider:

  • A maximum of 20 hits can be specified per request.

  • The combined size of all hit payloads cannot be greater than 16K bytes.

  • No single hit payload can be greater than 8K bytes.

  • The request needs to be done using POST

For our solution, each time the number of stored hits is more than 1, we send the payloads using the batch endpoint. In case there are too many hits stored in the queue, we’re chunking them so that multiple batch requests are sent in succession until the entire queue is processed.

5. Improvements

Keep in mind that this current post is meant to show how to track the hits that may happen while the user is offline (due to a connectivity gap). At the same time, we’ve taken the opportunity to showcase some cool and relatively little-known Google Analytics JavaScript API functionalities.

A solid improvement would be to skip the originalSendTask part, and just overwrite the sendHitTask task entirely. This way you can skip the HTTP HEAD request, because you can just check if the initial hit to Google Analytics is dispatched successfully.

The one thing you need to keep in mind if you want to overwrite the sendHitTask is that you’ll need to replicate the transport logic for the request. The analytics.js library supports three different ways to dispatch the requests:

  1. 'image' – max 2K payload size sent with a GET request to a pixel endpoint

  2. 'xhr' – max 8K payload size sent as an HTTP POST request

  3. 'beacon' – POST request that uses the navigator.sendBeacon() to make sure your requests are sent even if the user has already navigated away from the page

So you’ll need to replicate this logic in your custom sendHitTask method. It’s not exactly trivial to do, but an able developer should be able to do it, especially once the constraints (see previous paragraph) are known.

Another thing you might want to do is add a Custom Dimension to all the payloads that are stored in the queue. This Custom Dimension could be named something like Offline hit, and you should set the value to true if the hit was sent from the offline queue. Thus you can monitor how many hits in your data were initially aborted due to poor internet connectivity.

6. Summary

I’m really glad to have David guest star on this blog – it’s been a long time coming! This solution is great for two reasons. First, it’s actually very usable, especially if your site caters to mobile visitors. Second, it showcases a number of features of the web browser and the analytics.js library that can be extended to other purposes, too.

The Tasks API is really interesting, as it allows you to manipulate the payloads dispatched by the website. And with the introduction of customTask, we finally have a very handy way of accessing tasks with Google Tag Manager.

Note that if you have a web application with offline capabilities, and you are using service workers to manage this functionality, Google has released a useful library for employing service workers to do precisely the same thing we’re doing in this article.

We hope you enjoyed this solution! Let us know in the comments

Skip to toolbar