Overview
Containers wrap page content and add behavior based on visitor actions, page events, or other conditions.Available Containers
CTA Container
The CTA Container (call-to-action container) holds the part of a video sales letter (VSL) page that should stay hidden until the pitch: packages, prices, buy buttons, the guarantee. It opens when the page callsgetStarted(). Most of the time that call comes from the video player at the pitch timestamp, and you can also call it from a button, a Page Events flow or your own script.
Key Features:
- Hidden when the page loads, by the page head CSS (
display: none) - Opens (
display: block) whengetStarted()runs - Can scroll the visitor to itself when it opens
- Stays open for returning visitors (see Returning visitors)
The classes
Everything is driven by CSS classes. The builder adds them for you; in code you write them yourself.The TrackPlay V2 embed also ships a fallback
getStarted() that remembers the focus-on-cta scroll in a scrolled_<video code> cookie for one day. The page’s main script replaces that fallback as soon as it loads, so on a normal page the rules in the table apply.What getStarted() does
getStarted(focusOnCta = true) is a global function on every published page. Each call:
- Sets
window.showed_video_cta = true. - Saves the reveal for this browser:
localStoragekeyvideo_cta_shown=true, plus avideo_cta_showncookie for 365 days. - Opens every
.video-cta-containerand.show-on-video-cta, and hides every.hide-on-video-cta(all with!important). - If
focusOnCtais true and the CTA was not restored on this page load, scrolls to the first.video-cta-container.focus-on-cta. Without that class nothing scrolls. - Fires the
video-cta-shownwindow event with{ focus_on_cta, timestamp }.ef.onCta()listens for it. - Runs the nodes after any CTA: On Shown node in Page Events.
getStarted(false) opens the CTA without scrolling.
window.showed_video_cta is true once the CTA has been shown on this page load, either by getStarted() or by the returning-visitor restore. Read it in your own scripts to check whether the visitor reached the pitch. The If Showed CTA Page Events node and live order popups set to wait for the CTA read the same flag.
How TrackPlay fires it at the pitch
- In TrackPlay, open the video’s Timed events tab and add an event: Event Name (for example
cta) and Time (the pitch timestamp). When playback reaches that time the player emits an event with that name. Skipping ahead past the time fires it too. - The ElasticFunnels embed listens for that name and calls
getStarted():- TrackPlay Video (
<trackplay-video>): listens fordata-cta-event-name(defaultcta). Scrolling followsdata-focus-on-cta, which defaults to on. Only the value0turns it off;falsestill scrolls. - TrackPlay Video V2 (
<trackplay-video-v2>): listens for every event in itsdata-ctalist, each with its own scroll setting. The builder fills that list with all of the video’s timed events. If the attribute is missing, it listens forctawithout scrolling.
- TrackPlay Video (
- Turn on Call Once Per Session and Call on Subsequent Visits in TrackPlay and a returning viewer who already passed the pitch gets a
<event name>_subsequentevent straight away. The embed answers it withgetStarted(false), so the CTA opens without a scroll.
Returning visitors
Two mechanisms bring the CTA back on later visits:- Saved reveal. On every page load the main script checks
localStorageforvideo_cta_shown. If it is set, CTA containers open and hide-on-CTA content hides immediately, with no scroll and novideo-cta-shownevent. This key belongs to the domain, not to one page or one video, and it does not expire. - Open on return. Every TrackPlay embed writes
showed_cta_<video code>tolocalStoragewhen the page loads. If the key was already there from an earlier load, the embed callsgetStarted(false)about one second after load. A returning visitor gets the CTA whether or not they reached the pitch on the first visit, so someone who left early and came back to buy does not have to sit through the video again.
video_cta_shown and showed_cta_<video code> from localStorage, the video_cta_shown cookie, and TrackPlay’s trackplay_<event code> cookie.
Use it in a code page (.ef)
In a page you write in code, use the class names directly. A minimal VSL page:1500) → If Showed CTA → output 2 → Show Video CTA. Tick Scroll to CTA on the last node if the page should jump. See Page Events nodes.
To open the CTA from a button that is visible before the pitch (a “Skip to the offer” link, for example), call getStarted() from its click handler or from the Interactions Panel:
Use it in the builder
- Add the video. Drag Trackplay Video V2 (category External Integrations) onto the page. In its TrackPlay Video settings, pick your integration under Select TrackPlay Integration, then pick the video under Select a video.
- Choose which events open the CTA. The settings list the video’s timed events under CTA Events Available, each with its time. Every event listed opens the CTA. Tick Scroll to CTA Container on the events that should also scroll.
- Add the CTA Container. Drag CTA Container (category Offer) where the offer goes and build the packages inside it. The Container Settings panel confirms it is hidden when the page loads.
- Set its toggles. Focus on this when CTA is called adds
focus-on-cta, the scroll target. Show to returning viewers addscta-keep-visible-on-reload, the open-on-return setting. - Optional: hide content at the pitch. Wrap it in Container: Hide on Video CTA (category Offer).
Pitfalls
- Everything inside is invisible until the pitch. The head CSS hides the container before any script runs, so its content does not show in a quick look at the live page, in a screenshot taken early, or to a visitor whose video never fired. Always give it a fallback (a timer, a skip link or a Page Events flow).
- Widgets that measure themselves at load. A slider, carousel or countdown inside the container starts while it has no size. Check it after the reveal, or start it from
ef.onCta(). - Do not set
displayon the container yourself. On code pages the hiding rule is a plaindisplay: none, so your owndisplay: flexon.video-cta-containercan show it at load. Put layout on a wrapper inside it. After the reveal the container isdisplay: block !important. - Several videos on one page. There is one CTA for the whole page. Whichever video reaches a CTA event first opens every
.video-cta-container, and there is no way to pair a container with one video. Each embed’s listener is attached to every TrackPlay player that loads on the page, so a timed event name used by a second video (a testimonial with its ownctaevent, for example) opens the offer too. Give events on secondary videos different names. Open on return also works per video, so any of the page’s videos can open the CTA on a later load. - The saved reveal covers the whole domain. A visitor who reached the pitch on one page sees CTA containers open at load on every other page of that domain, including the other arm of a split test. Test pitch timing in a fresh private window.
- The builder lists every timed event. If the video has timed events for other jobs (a pixel, a bonus reveal), they open the CTA as well. Keep CTA events on the pitch, or remove the others from the video. A video with no timed events never opens the CTA by itself.
- CTA: On Shown runs on every
getStarted()call, including the open-on-return call about one second after load and_subsequentevents. Keep the nodes after it safe to repeat. - Page classification. ElasticFunnels’ page analysis counts a builder video block, CTA Container or Hide on CTA as one of the signals that a page is a VSL. It reads builder component types, so a code page that uses only the class names does not give that signal. Its buy links still count.
- Reveal packages and buy buttons at the VSL pitch
- Remove “keep watching” copy once the offer is on screen
- Give visitors who skip around a button that opens the offer
- Open the offer on a timer for visitors whose video never reaches the pitch
Hide on CTA Container
The Hide on CTA Container is the opposite of the CTA Container. It is visible when the page loads and hidden whengetStarted() runs. In code it is any element with the class hide-on-video-cta; in the builder it is the Container: Hide on Video CTA block.
Key Features:
- Visible by default
- Hidden (
display: none !important) whengetStarted()runs - Stays hidden for returning visitors once the CTA has been shown in that browser
- The Hide Video CTA Page Events node shows it again (and hides the CTA Container)
- “Keep watching” or “the offer appears below” notes
- A lead-in headline that should give way to the offer
- Content that should not sit next to the buy buttons
Merchant Container
The Merchant Container displays content conditionally based on the active payment processor (merchant) for the current page view. Key Features:- Shows content only for specific merchants
- Hides all non-matching merchant containers
- Can be set per domain or overridden in Page Events
- Useful for merchant-specific disclaimers, policies, and branding
- Domain-Level Setting: Default merchant set in Domain settings
- Page Events Override: Use the “Set Merchant” node in Page Events to override for specific conditions
- Buygoods
- Clickbank
- Digistore24
- Other configured payment processors
- Add Merchant Container to your page
- Select Merchant from the container settings
- Add Content specific to that merchant
- Repeat for each merchant you want to support
- Merchant-specific disclaimers and legal policies
- Payment processor-specific trust badges and seals
- Different refund policies based on merchant
- Merchant-specific support information and contact details
- Custom branding elements per merchant
- Merchant-specific terms and conditions
- Go to Page Events for your page
- Add a condition (Query Parameter, Script Rule, etc.)
- Connect to Set Merchant node
- Select the merchant to activate
- Merchant containers will show/hide accordingly
- Add Clear Merchant node in Page Events
- Connect it to a condition or event
- When triggered, clears any session merchant override
- Page returns to using the domain’s default merchant
- Resetting test merchants back to production
- Clearing affiliate-specific merchants after purchase
- Returning to default after special conditions expire
If no merchant is set (neither at domain level nor via Page Events), merchant containers will not display. Ensure you have a default merchant configured.
Split Test Container
The Split Test Container marks a section of the page whose content is chosen by a traffic split. It renders as a<split-test> element and holds no logic of its own — the variants and their weights live in Page Events.
Key Features:
- Marks one swappable slot, identified by its
id - Filled by a Component Split Test node in Page Events
- Its inner content is the default — what renders when no split test is running
- Each served variant is tagged for analytics (
data-sid/data-cid)
- Add a Split Test Container to your page and fill in its Split Test Container Name trait — that name is what you pick from in Page Events.
- Create one saved component per variant.
- Configure in Page Events:
- Add a Component Split Test node and select the container
- Set Total Variants — a Traffic Distribution node is created for each one
- Attach one Component node under each Traffic Distribution node, and mark one as the baseline
- Track Results in Analytics
- Test different headlines
- Compare pricing presentations
- Test different images or videos
- Optimize form layouts
- Test one element at a time
- Run tests long enough for statistical significance
- Track meaningful conversion goals
- Document your test results
Lazy Load Container
The Lazy Load Container defers loading of content inside it until the visitor scrolls to that section of the page. Key Features:- Improves initial page load performance
- Loads content “just in time” when visitor scrolls near it
- Reduces bandwidth for content visitors never see
- Loads when needed without interrupting the page
- Page loads with empty lazy load containers
- Visitor scrolls down the page
- When container enters viewport (or approaches it), content loads
- Content appears smoothly without page disruption
- Below-the-fold content
- Large images or videos
- Comment sections
- Secondary information
- Resource-heavy widgets or embeds
- Above-the-fold content
- Critical purchase buttons
- Forms that need immediate interaction
- Content needed for SEO
- Use for content below the fold only
- Combine with image optimization
- Test on slow connections
- Monitor Core Web Vitals impact
Related Containers
Some specialized containers are documented in dedicated pages:Subscription Containers
Sub Pending, Sub Success, and Sub Error containers auto-toggle based on the result of a subscription modification API call (ef.sub.upgrade() / ef.sub.cancel()). Use them to build multi-screen subscription upsell flows.
View Subscription Upsells Documentation →
Dynamic Container
The Dynamic Container marks a slot whose content is replaced with a saved component when a Page Events condition matches. Unlike the Split Test Container, the choice is driven by a condition you write, not by a traffic split. View Dynamic Content Documentation →Whitelisted Containers
Whitelisted Container and Non-Whitelisted Container display different content based on visitor whitelisting status, commonly used for content protection and personalized visitor experiences. View Content Visibility Control Documentation →Container Combination Patterns
Progressive Sales Flow
Combine multiple containers for a complete sales experience:Performance-Optimized Page
Use lazy loading for better page speed:Dynamic Merchant Selection
Adapt disclaimers and policies based on traffic source:Best Practices
Container Organization
- Clear Naming: Name containers descriptively in the page builder
- Document Logic: Note which containers work together
- Test All Paths: Verify all show/hide conditions work correctly
- Consider Mobile: Ensure container behaviors work on all devices
Performance Guidelines
- Lazy Load Wisely: Use for below-fold content only
- Minimize Nesting: Don’t nest containers unnecessarily
- Test Load Times: Monitor impact on page speed
- Optimize Content: Compress images and minimize resources inside containers
User Experience
- Smooth Transitions: Avoid jarring content shifts when containers appear
- Visual Feedback: Let users know when content is loading
- Fallback Content: Have defaults for when conditions aren’t met
- Test Edge Cases: What happens if no merchant is set? Test it.
Development Workflow
- Start Simple: Add containers one at a time
- Test Immediately: Verify each container works before adding more
- Use Preview Mode: Test without affecting live traffic
- Clear Cache: Clear browser cache when testing changes
Troubleshooting
CTA Container Not Showing
Symptoms: CTA container remains hidden after trigger Possible Causes:- The TrackPlay timed event name does not match the name the embed listens for (exact match, case included)
- A builder TrackPlay Video V2 whose video has no timed events, so nothing calls
getStarted() - The content sits outside the element with the
video-cta-containerclass - A JavaScript error on the page stops the main script
- Run
getStarted()in the browser console. If the container opens, the page is fine and the trigger is the problem. - Compare the event name in TrackPlay’s Timed events tab with
data-cta-event-name(V1) or the CTA Events Available list (V2). - Check the browser console for JavaScript errors
- Add a fallback timer or a skip button (see Use it in a code page)
CTA Opens Too Early or on Load
Symptoms: The offer is visible before the pitch, or right after the page loads Possible Causes:- The browser already saw the CTA on this domain (
video_cta_showninlocalStorage) - Open on return: the browser loaded this video’s page before (
showed_cta_<video code>), so the CTA opens about one second after load. This is intended for returning visitors - Another timed event on the video, or on a second video on the page, opens it
- Your own CSS sets
displayon.video-cta-container
- Test in a fresh private window
- Check the video’s timed events and rename the ones that are not the pitch
- Move layout CSS to a wrapper inside the container
Merchant Container Not Displaying
Symptoms: No merchant containers showing Possible Causes:- No merchant set at domain level
- No merchant selected in Page Events
- Merchant ID mismatch
- Check domain settings for default merchant
- Verify Set Merchant node in Page Events
- Confirm merchant containers have correct merchant assigned
- Check browser console for errors
Lazy Load Issues
Symptoms: Content not loading when scrolling Possible Causes:- Container too small to trigger
- JavaScript not initializing properly
- Content inside container has errors
- Ensure container has minimum height
- Check browser console for errors
- Test without lazy loading first
- Verify content loads normally outside container
Multiple Containers Conflicting
Symptoms: Unexpected show/hide behavior Possible Causes:- Overlapping container logic
- Multiple merchants set incorrectly
- CTA and Hide on CTA not paired properly
- Review Page Events flow carefully
- Test each container individually
- Check for conflicting JavaScript
- Simplify logic and add complexity gradually
Related Documentation
- Page Events - Set up merchant switching and complex flows
- Dynamic Content - Learn about Dynamic Containers
- Content Visibility Control - Whitelisting containers
- Split Testing - A/B testing with containers
- Interactions Panel - Add click handlers to trigger CTAs
Start with one clear container use case, then add more logic only when you can test each condition.