Back

SPFx Audience targeting

Apr 9, 2024 min read

Audience Targeting 🎯

Audience targeting allows content administrators to direct content toward specific groups of users. This is particularly useful in organizations with a wide array of users, where not all content is relevant for everyone. By using audience targeting, you can improve the relevance of the content each user sees, leading to a more personalized and focused user experience.

Audience Targeted Wrapper 🔧

Let’s dive into how to build an SPFx component that employs audience targeting. This component acts as a wrapper, showing or hiding content based on the user’s membership in specific groups.

Group Check Logic 🔍

At the heart of our component is the logic that determines if the current user is a member of any of the specified groups.

Group Check Logic

public async isMember(group: any, context: any): Promise<boolean> {
    const _cacheName = 'CacheName_memberGroups';

    if (group == null || group == '') {
        return true;
    }
    const graph = graphfi().using(SPFx(context));
    let _cachedMemberGroups = sessionStorage.getItem(_cacheName);
    let memberGroups: string[] = [];
    if (!_cachedMemberGroups) {
        memberGroups = await graph.me.getMemberGroups();
        sessionStorage.setItem(_cacheName, JSON.stringify(memberGroups));
    } else {
        memberGroups = JSON.parse(_cachedMemberGroups);
    }
    // "c:0o.c|federateddirectoryclaimprovider|xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
    const groupID = group.id.split('|')[2];
    if (memberGroups.filter((g: string) => g === groupID).length > 0) {
        return true;
    }
    throw new Error('User not found');
}

The wrapper component is visually minimalistic, primarily designed to function based on the logic of accessing group IDs from an array of IPropertyFieldGroupOrPerson. Its simplicity belies its utility, enabling dynamic content visibility tailored to user or group permissions with little visual footprint.

TargetAudience wrapper

export interface ITargetAudienceProps {
    pageContext: PageContext;
    context: any;
    groupIds: IPropertyFieldGroupOrPerson[];
}

const TargetAudience: React.FC<ITargetAudienceProps> = ({ pageContext, groupIds, children, context }) => {
    const [canView, setCanView] = useState<boolean>(false);

    useEffect(() => {
        const checkUserIsAllowedToViewWebpart = async () => {
            let proms: any[] = [];
            const errors: any[] = [];
            groupIds?.map((item : any) => {
                proms.push(
                    isMember(item, context)
                );
            });
            Promise.race(
                proms.map(p => {
                    return p.catch((err: any) => {
                        errors.push(err);
                        if (errors.length >= proms.length){
                            throw errors;
                        } 
                        return Promise.race(null);
                    });
                }))
                .then(val => {
                    setCanView(true);
                });
        };
        checkUserIsAllowedToViewWebpart();
    }, [groupIds, pageContext]);

    return (
        <div>
            {groupIds != null && groupIds.length >= 1 ? (canView ? children : '') : children}
        </div>
    );
};

export default TargetAudience;

How to use it

<TargetAudience groupIds={GroupsIDS} pageContext={pageContext} context={context}>
    <h1>
        This is top secret for non admins...
    </h1>
</TargetAudience>

Final Thoughts 💭

Could the logic be extended to check that only selected users can view the content, instead of it being limited to groups? Absolutely, this is entirely possible.

However, I’ve chosen to focus on the group aspect because that’s often what my solutions revolve around. This approach emphasizes the flexibility of SPFx solutions in catering to diverse requirements, allowing for both broad group-based targeting and the precision of user-specific content visibility.

It highlights the potential to tailor your SharePoint solutions even more closely to your organization’s needs, ensuring that every piece of content reaches exactly the right audience.

Jeppe Spanggaard

A passionate software developer. I love to build software that makes a difference!