Overview
Data rarely arrives in one place. GA4 sessions live in one table, ad spend in another, and an offline conversion export in a third. Each is useful alone, but the interesting questions, like cost per session by channel, need all three lined up together. A join table does that lining up.
A join table has no external source of its own. It starts from a base table and joins additional tables onto it, matching rows on join keys, which are the dimensions the tables have in common. The output is a single wider table where each row carries the columns from every joined source. Boards and reports then query that one table instead of stitching numbers together by hand.
A join adds columns. If you instead need to stack rows from similar tables, that is a Union, and if you need to reshape a single table, that is a Pivot. Reach for a join specifically when different tables hold different measures for the same entities.
Prepare the tables to join
Because a join reads from other Lens tables, every table you want to combine must already exist and have synced successfully. A join cannot pull data that its sources have not loaded yet.
Just as important, the tables must share at least one dimension you can match on. Date is the most common join key, often paired with a second dimension like source or campaign. Before you build the join, confirm those shared columns exist in every table and are named and formatted consistently, because the join matches on exact values.
Create the join table
Open Lens > Tables from the left sidebar and click Add Table. Choose Join as the source type. The setup page switches to the join layout, and the breadcrumb reads "New Joined Table".
Give the table a name that describes the combined result, such as "Sessions and Spend by Channel". This is the table boards will reference, so a clear name saves confusion later.
Pick the base table
Choose the base table. The base is the starting set of rows for the join, and every joined table adds its columns onto those rows. The base determines which rows can appear in the output, so pick the table whose row coverage you want to anchor on.
As a rule of thumb, make the most complete table the base. If GA4 sessions cover every day but ad spend only covers days a campaign ran, use sessions as the base so you keep every day and simply see blank spend on the quiet days.
Add joined tables and keys
Add one or more tables to join onto the base. For each, choose the join keys, the shared dimensions used to match rows. A join on date alone matches one row per day. A join on date plus source matches one row per day per source, which is usually what channel-level analysis needs.
Pick keys that exist in every table being joined and that hold the same values in each. A mismatch, such as one table storing google and another storing Google, will cause rows to fail to match even though they look related. Consistency on the upstream side is what makes a join behave.
Save and build
Click Save, then build the join. Lens runs the join query and stores the combined result as its own ClickHouse table, so boards query the join directly with no extra work at view time.
A join is a snapshot of its sources at build time. Whenever any source table re-syncs with new data, rebuild the join so it reflects the change. The table view flags when a rebuild is due.
Joins only emit rows where the keys match. If you want to keep every row from the base even when a joined table has no match, make sure the base table is the one with the fullest coverage. The base anchors the output.
A join table is only as fresh as its sources. If any source syncs on a schedule, the join drifts behind until you rebuild it. For dashboards that must stay current, rebuild the join after its sources refresh.
Troubleshooting
The join shows fewer rows than expected
A join only emits rows where the join key matches across the tables. If one source has dates or values the other does not, those rows drop out. Open each source table and compare the coverage of the join-key columns. The fix is almost always on the upstream side, by widening a source's date range or aligning its key values, rather than in the join itself.
The join reports a source table is missing
One of the joined tables was deleted or moved. The join view shows a notice naming the missing table. Open the join configuration, point it at a valid table, and rebuild. Lens normally blocks deleting a table that a join depends on, so this usually means the dependency chain was broken in an unusual way.
A joined column comes back empty
The rows matched on the join key, but the joined table had no value to contribute, or its key values did not line up. Check for formatting differences between the key columns, such as casing or leading spaces. Also confirm the joined table actually synced data for the dates in question.