Docs > Xamarin SDK

Xamarin SDK



Copy link to clipboard


Download and Installation

Copy link to clipboard

You need two parts to get the most out of the SDK for Xamarin.

  • add-in (providing settings management)
  • SDK library files

Both parts can be downloaded directly from the Github repository

When building for iOS the SDK only supports iOS Unified builds.

Add-in package download

Github Repository

Use the download button below to download the latest add-in package directly from the github repository.

Unzip the downloaded .zip and take note of the .mpack file location.
To install the add-in do the following depending on what OS you are on.

  • Mac: Xamarin Studio -> Add-in Manager…-> Install from file…-> [select .mpack file]
  • Windows: Tools-> Add-in Manager…-> Install from file…-> [select .mpack file]

Ignore this potential error message that might show up at the end of the add-in installation about failing to read the description. This is a known Xamarin bug. Just disregard it.

SDK library files

Xamarin Component Store (recommended)

To install the SDK library files from the Xamarin Component Store do the following:

  1. In your project right-click on the Components folder
  2. Choose Get more Components
  3. In Xamarin Component Store window search for GameAnalytics SDK
  4. Click on the newly found component
  5. Click on Add to App to add the component to your project

Make sure to update the installed packages to the latest version by right-clicking on the Packages and choose Update.

Github Repository

To install the SDK library files from the Github repository do the following:

  • Download the .zip file from this repository here
  • Unzip the downloaded file
  • Depending on your target platform add the following files to the project’s references:
    • Android:
      • GameAnalytics.Android.dll
      • GameAnalytics.Android.Jar.dll
    • iOS:
      • GameAnalytics.iOS.dll

For Android you must also add some additional packages. Right-click on Packages folder,
choose Add packages… and add the following:


Target Android version must API level 22 or higher and for iOS 8.1 or higher.


Sign up and login

Copy link to clipboard

To use GameAnalytics you need a game key and a game secret for each platform you are using (iOS/Android).

game key is a unique identifier for your game.
secrect key is used to protect event data from being tampered with as it travels to the GameAnalytics servers.

Using the Xamarin Studio add-in (settings) it is possible to sign up/login and then create/retrieve these keys automatically.

Sign up

To sign up with Xamarin right-click on your project and choose Options in the context menu and scroll down to the GameAnalytics section. Under any of the menu items in this section you can click on the Sign up button to sign up.
During this process an account will be created with a studio containing one game.
You will be automatically logged in afterwards.

After you have signed up you will be asked to create a game. If your game is already published and in the app store, you can search for it using the provided app store search or you can create a new game.


To login right-click on your project and choose Options in the context menu and scroll down to the GameAnalytics section. Under any of the menu item in this section you can click on the Login button to open the login dialog and enter your credentials.

After succesful login under the Setup menu item you can select a studio and game. When a game is selected, the game key and secret key will be automatically fetched and configured.

Once a game has been created it can take a few minutes before the GameAnalytics servers will accept events for that game.
You can of course always create games manually in our tool and locate the keys in the game settings.


Configure Xamarin

Copy link to clipboard

To access settings you need to right-click on your project, choose Options in the context menu and scroll down to the GameAnalytics section. Settings is divided into the menu items Setup, Custom and Advanced.
Once you are finished with configuring everything you can click on “Save changes” under any of the panels, this will create or update the GA_Config.cs file. When clicking ‘OK’ in the Options pop-up window the settings values will be saved in the GA.addin.config file under the project for saving the values for next time you open the Options window.

ANDROID GAMES: Remember to set following permissions for the application (under Android Application): AccessNetworkState and Internet.


In the Setup tab you specify the game keys, secret keys and the build version for each platform.

Game Key + Secret Key

For each platform (iOS/Android) you need to configure a set of game keys.

game key is a unique identifier for your game.
secrect key is used to protect event data from being tampered with as it travels to the GameAnalytics servers.


Build is used to specify the current version of your game. Specify it using a string.
Recommended to use a 3 digit version like: [major].[minor].[patch]

The build version should be used for changing proudction builds of the game.
We recommend creating a separate game when implementing or testing the SDK.


Here you can configure available custom dimensions and resource types.

Custom Dimensions

During gameplay it is possible to set values for 3 different custom dimensions. For each custom dimension it is needed to specify a whitelist. You cannot set a custom dimension value unless it is specified here first.

For more information about custom dimensions go here.

Resource Types

When submitting resource events you specify a resource currency and resource item type. It is needed to specify a whitelist for each of these. You cannot submit a resource event using other values than specified here.


Advanced settings

Submit Errors

Enable this to catch error and exception messages within Xamarin when the game is running and submit them to GameAnalytics. This is useful for discovering unforeseen issues after the game has been launched. It will submit an error event using the type error, warning or critical.

After a game has been launched it will only send a maximum of 10 error events automatically. Some games can generate a lot of exceptions and this cap will prevent degraded performance and unintended bandwidth usage.

Debug Settings

The SDK is designed to be as silent as possible and use few resources. You will therefore not get much information by default when actions or errors occur.

Info Log Build

The info log will output basic information about what is happening when your game is built for native.

Verbose Log Build

The verbose log will output the event JSON data that is being sent to the GameAnalytics servers when your game is built for native.


initialize sdk

Copy link to clipboard


Using the SDK

Copy link to clipboard

Now we should be ready for adding code to activate the SDK!

  1. Configuration
  2. Initialization
  3. Adding events or changing dimensions

The configuration and initialization steps should be called inside the FinishedLaunching located in the AppDelegate class for iOS class and inside OnCreate located in the MainActivity class for Android.

The configuration and initialization steps can be done manually or by using the values saved in GA_Config using the Xamarin SDK add-in like so which will set all configurations and call initialize:

// Android:
 GameAnalytics.Initialize(this, GA_Config.Json);

 // iOS:

Once step 1 & 2 is done you can add events at different parts of the game code where some relevant action is happening.

Remember to add the GameAnalyticsSDK namespace whenever you need to call the SDK.

using GameAnalyticsSDK;


Copy link to clipboard

The configuration phase happens before initialization is called. The available configuration options are listed here:

  • build
  • available (allowed) custom dimensions
  • available (allowed) resource currencies
  • available (allowed) resource item types


Build is used to specify the current version of your game. Specify it using a string. Recommended to use a 3 digit version like: [major].[minor].[patch]


Auto detect app version to use for build field
There is an option to auto detect app version to use for build field. Just call this before intializing the SDK:

//Set build version
GameAnalytics.SetBuild("alpha 0.1.0");

User ID

The SDK will automatically generate a user id and this is perfectly fine for almost all cases. Sometimes it is useful to supply this user_id manually – for example if you download raw data for processing and need to match your internal user id (could be a database index on your user table) to the data collected through GameAnalytics.

Note that if you introduce this into a game that is already deployed (using the automatic id) it will start counting existing users as new users and your metrics will be affected. Use this from the start of the app lifetime.


Specifying allowed values

For certain types it is required to define a whitelist containing possible unique values during the configuration phase. When the SDK is being used (after initialization) only the specified values will be allowed. 20 values are allowed for each list.

Processing many unique dimension values can be taxing on our servers. A few games with a poor implementation can seriously increase our cost and stability. We will block games that submit too many unique dimension values. Therefore we have this requirement in the SDK to guide users into planning their dimension values.

GameAnalytics.SetAvailableResourceCurrencies("gems", "gold");
 GameAnalytics.SetAvailableResourceItemTypes("boost", "lives");

 // Set available custom dimensions
 GameAnalytics.SetAvailableCustomDimensions01("ninja", "samurai");
 GameAnalytics.SetAvailableCustomDimensions02("whale", "dolphin");
 GameAnalytics.SetAvailableCustomDimensions03("horde", "alliance");

Each resource currency string should only contain [A-Za-z] characters.

Enable/disable event submission

If you for GDPR purposes need to disable event submission you can call the following:


By default event submission is of course enabled. You will still receive configs if you have set any for your game even after disabling event submission.



Copy link to clipboard
Below is an example on how to use the saved values from the Xamarin SDK add-in.

using GameAnalyticsSDK;

 public class AppDelegate : UIApplicationDelegate

     public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)

         // ... other code from your project ...

         // Initialize from json

         return true;



using GameAnalyticsSDK;

 public class MainActivity : Activity

     protected override void OnCreate (Bundle bundle)

         // ... other code from your project ...

         // Initialize from json
         GameAnalytics.Initialize(this, GA_Config.Json);


adding events

Copy link to clipboard


Copy link to clipboard

GameAnalytics feature the following event types.

Event Description
Business In-App Purchases supporting receipt validation on GA servers.
Resource Managing the flow of virtual currencies – like gems or lives.
Progression Level attempts with Start, Fail & Complete event.
Error Submit exception stack traces or custom error messages.
Design Submit custom event id’s. Useful for tracking metrics specifically needed for your game.

Please read our event guide here. You will get the most benefit of GameAnalytics when understanding what and how to track.



Copy link to clipboard

Business events are used to track in-game transactions using real money.
Jailbroken devices can pollute this metric and we therefore provide receipt validation. Submit the receipt with the event and the GA servers will then validate the transaction.

Business event with receipt

When an in-app purchase is completed you should call the following method to add a business event:

 GameAnalytics.NewBusinessEvent("USD", 999, "Weapon", "SwordOfFire", "Menu", **receipt string**, false);
Field Type Description Example
currency string Currency code in ISO 4217 format.
amount integer Amount in cents. 99 is 0.99$
itemType string The type / category of the item. GoldPacks
itemId string Specific item bought. 1000GoldPack
cartType string The game location of the purchase.
Max 10 unique values.

If the receipt is null (or is an invalid receipt) and autoFetchReceipt=false then the GA servers will register that amount as not validated.

Android receipt json schema

    "orderId": "",
    "packageName": "",
    "productId": "",
    "purchaseTime": 1484080095335,
    "purchaseState": 0,
    "purchaseToken": ""

This will be encoded to base64 by the GameAnalytics Android library. As a result you should pass a string similar to the json above.

Business event with auto fetch receipt (iOS 7+)

Using an alternative method it is possible to let the SDK retrieve the receipt automatically when called directly after a successful in-app purchase. The code performed by the SDK is identical (almost) to the objective-c example above for iOS7+.

Using this method on iOS6.x devices will cause the business event to be ignored.

GameAnalytics.NewBusinessEvent("USD", 999, "Weapon", "SwordOfFire", "Menu", null, true);

For more information about the business event go here.

The GameAnalytics ad event needs to be called when certain events happen for the implemented ad sdk’s.
An ad sdk has callback methods activating code when certain things are activated (like ad show or ad clicked).

To use the ad event it is need to call the GameAnalytics SDK when these delegates are called.

The examples below describe how to implement this for the following ad-types.
– rewarded video
– interstitial
– bannner

All code examples use AdMob SDK to showcase example usage.
Other ad networks might differ in naming/structure, but the overall process should be applicable to all.

The ad SDK name argument for the ad event needs to be all lower-case with no spaces or underscore used. Here some examples of valid values to use for ad SDK names:
– admob
– unityads
– ironsource
– applovin



  • When you want to show an ad, it is either available or not.
  • Call the ad event, when the ad is not available.
  • We do not call ad event on show, as we call it on ad close later.
if (this.rewardedAd.IsLoaded()) {
    GameAnalytics.NewAdEvent(GAAdAction.FailedShow, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");


  • If you want to track rewards from rewarded videos, then call an ad event in the method where rewards are registered.
  • For admob this delegate is called OnUserEarnedReward and the following example is a method for how you could handle this.
public void HandleUserEarnedReward(object sender, Reward args) {
    // send ad event - reward recieved
    GameAnalytics.NewAdEvent(GAAdAction.RewardReceived, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");


  • We track the rewarded ad when it has finished being shown.
  • For admob this delegate is called OnAdClosed and the following example is a method for how you could handle this.
public void HandleRewardedAdClosed(object sender, EventArgs args) {
    if(currentRewardedVideoPlacement != null)
        long elapsedTime = GameAnalytics.StopTimer(currentRewardedVideoPlacement);
        // send ad event for tracking elapsedTime
        GameAnalytics.NewAdEvent(GAAdAction.Show, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]", elapsedTime);
        currentRewardedVideoPlacement = null;

        // OR if you do not wish to track time

        // send ad event without tracking elapsedTime
        GameAnalytics.NewAdEvent(GAAdAction.Show, GAAdType.RewardedVideo, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");



  • When you want to show an ad, it is either available or not.
  • Call the ad event, when the ad is not available.
if (this.interstitial.IsLoaded()) {
    GameAnalytics.NewAdEvent(GAAdAction.FailedShow, GAAdType.Interstitial, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");


  • For interstitials we track an event at the time it is being shown
  • The following example is a method for how you could handle this.
public void HandleInterstitialOpened(object sender, EventArgs args) {
    // send ad event
    GameAnalytics.NewAdEvent(GAAdAction.Show, GAAdType.Interstitial,"admob", "[AD_PLACEMENT_OR_UNIT_ID]");


  • Call event when delegate OnAdLeavingApplication is called
  • The following example is a method for how you could handle this.
public void HandleInterstitialLeftApplication(object sender, EventArgs args) {
    // send ad event - ad click
    GameAnalytics.NewAdEvent(GAAdAction.Clicked, GAAdType.Interstitial,"admob", "[AD_PLACEMENT_OR_UNIT_ID]");



  • If the ad loads successfully send the following ad event when OnAdLoaded delegate is called.
  • The following example is a method for how you could handle this.
public void HandleAdLoaded(object sender, EventArgs args) {
    GameAnalytics.NewAdEvent(GAAdAction.Show, GAAdType.Banner,"admob", "[AD_PLACEMENT_OR_UNIT_ID]");


  • For admob the banner ad click is registered on the OnAdOpening delegate callback.
  • Call an ad event at this time for banner ads.
  • The following example is a method for how you could handle this.
public void HandleAdOpened(object sender, EventArgs args) {
    // send ad event
    GameAnalytics.NewAdEvent(GAAdAction.Clicked, GAAdType.Banner, "admob", "[AD_PLACEMENT_OR_UNIT_ID]");
Field Type Description Example
adAction enum A defined enum for ad action (for example clicked). GAAdAction.Clicked
adType enum A defined enum for ad type (for example interstitial). GAAdType.Video
adSdkName string Name of the Ad/Ad mediation SDK. admob
adPlacement string Identifier of ad in the game or the placement of it. level_complete_ad
duration int Optional. Only used for video ads to track how long the user watched the video for. 10
noAdReason enum Optional. Used to track the reason for not being able to show an ad when needed (for example no fill). GAAdError.Unknown

For more information about the ad event go here.



Copy link to clipboard

Resource events are used to register the flow of your in-game economy (virtual currencies) – the sink (subtract) and the source (add) for each virtual currency.

Before calling the resource event it is needed to specify what discrete values can be used for currencies and item types in the Configuration phase.

source (add) Gem currency from an in-app purchase.

 GameAnalytics.NewResourceEvent(GAResourceFlowType.Source, "Gems", 400, "IAP", "Coins400");

sink (subtract) Gem currency to buy an item.

 GameAnalytics.NewResourceEvent(GAResourceFlowType.Sink, "Gems", 400, "Weapons", "SwordOfFire");

sink (subtract) Gem currency to source (buy) some amount of another virtual currency (BeamBooster).

GameAnalytics.NewResourceEvent(GAResourceFlowType.Sink, "Gems", 100, "Boosters", "BeamBooster5Pack");

 GameAnalytics.NewResourceEvent(GAResourceFlowType.Source, "BeamBooster", 5, "Gems", "BeamBooster5Pack");

sink (subtract) 3 BeamBooster currency that were used during a level.

 GameAnalytics.NewResourceEvent(GAResourceFlowType.Sink, "BeamBooster", 3, "Gameplay", "BeamBooster5Pack");
Field Type Description Example
flowType enum A defined enum for sourcing and sinking resources. gameanalytics.EGAResourceFlowType.Sink
currency string The resource type/currency to track. Has to be one of the configured available resource currencies.
This string can only contain [A-Za-z] characters.
Gems, BeamBoosters, Coins
amount float Amount sourced or sinked. 0 or negative numbers are not allowed. 100.0
itemType string For sink events it can describe an item category you are buying (Weapons) or a place (Gameplay) the currency was consumed. For source events it can describe how the currency was gained. For example “IAP” (for in-app purchase) or from using another currency (Gems). Has to be one of the configured available itemTypes. Weapons, IAP, Gameplay, Boosters
itemId string For sink events it can describe the specific item (SwordOfFire) gained. If consumed during Gameplay you can simply use “Consumed”. For source events it describes how the player got the added currency. This could be buying a pack (BoosterPack5) or earned through Gameplay when completing a level (LevelEnd). BoosterPack5, SwordOfFire, LevelEnd, Coins400

Be careful to not call the resource event too often! In a game where the user collect coins fairly fast you should not call a Source event on each pickup. Instead you should count the coins and send a single Source event when the user either complete or fail the level.

For more information about the resource event go here.



Copy link to clipboard

Progression events are used to track attempts at completing some part of a game (level, area). A defined area follow a 3 tier hierarchy structure (could be world:stage:level) to indicate what part of the game the player is trying to complete.

When a player is starting a progression attempt a start event should be added.
When the player then finishes the attempt a fail or complete event should be added along with a score if needed.

Add a progression start event.

 GameAnalytics.NewProgressionEvent(GAProgressionStatus.Start, "world01", "stage01", "level01");

It is not required to use all 3 if your game does not have them.

  • progression01
  • progression01 and progression02
  • progression01 and progression02 and progression03
Field Type Description Example
progressionStatus enum Status of added progression gameanalytics.EGAProgressionStatus.Start gameanalytics.EGAProgressionStatus.Fail gameanalytics.EGAProgressionStatus.Complete
progression01 string Required progression location. World01
progression02 string Not required. Use if needed. Stage01
progression03 string Not required. Use if needed. Level01
score integer An optional score when a user completes or fails a progression attempt. Remember to set progression02 and/or progression03 if they are not used when using score parameter. 1023

For more information about the progression event go here.



Copy link to clipboard

Error Events

Used to track custom error events in the game. You can group the events by severity level and attach a message.

To add a custom error event call the following function:

 GameAnalytics.NewErrorEvent(GAErrorSeverity.Debug, "Something went bad in some of the smelly code!");
Field Type Description Example
severity enum Severity of error gameanalytics.EGAErrorSeverity.Debug
message string Error message (can be null) “Error when entering level12”

For more information about the error event go here.



Copy link to clipboard

Every game is special. Therefore some needed events might not be covered by our other event types. The design event is available for you to add your own event-id hierarchy.

Please note that custom dimensions and progression filters will not be added on design and error events. Therefore you cannot (at the moment) filter by these when viewing design or error metrics.

To add a design event call the following method.


It is also possible to add a float value to the event.
This will (in addition to count) make the mean and sum aggregation available in the tool.

 GameAnalytics.NewDesignEvent("BossFights:FireLord:KillTimeUsed", 234);
Field Type Description Example
eventId string The eventId is a hierarchy string that can consist of 1-5 segments separated by ‘:’. Each segment can have a max length of 32. The segments can be written only with a-zA-Z0-9 characters. “StartGame:ClassLevel1_5”, “StartGame:ClassLevel6_10”
value float A float event tied to the eventId. Will result in sum & mean values being available. 34.5

For more information about the design event go here.


remote configs & a/b testing

Copy link to clipboard


Remote Configs

Copy link to clipboard

To manual check if Remote Configs is ready (has been populated with values) you can call this:

    // the remote configs is ready, add your code here

Remember the remote configs can be populated with an empty dictionary if the device is offline and there are no cached remote configs from a previous session.

To get values out of a populated Remote Configs use the following methods:

// Without custom default value (using normal default value)
string value = GameAnalytics.GetRemoteConfigsValueAsString("key");
// With custom default value
string valueWithCustomDefaultValue = GameAnalytics.GetRemoteConfigsValueAsString("key", "myDefaultValue");

If the specified key is not found in the Remote Configs it will return the default value either “normal” or “custom” default value.


A/B Testing

Copy link to clipboard

To get the value of A/B testing id or variant id use the following methods:

// A/B testing id
string abTestingId = GameAnalytics.GetABTestingId();

// A/B testing variant id
string abTestingVariantId = GameAnalytics.GetABTestingVariantId();

Remember the A/B testing ids are first available when the Remote Configs are ready.


custom dimensions

Copy link to clipboard

Using Custom Dimensions

Copy link to clipboard

GameAnalytics support the use of 3 custom dimensions.

  • Custom01
  • Custom02
  • Custom03

During the game it is possible to set the active value for each custom dimension dynamically. Once a dimension is set it will be persisted across sessions/game-start and automatically be added to all event categories. Remember you have to set the custom dimensions before initialzing the SDK (but after setting the available custom dimensions) to be able to add the dimensions to the first session start event.

Setting each custom dimension. To reset a set custom dimension simply just set it to empty string.

Field Type Description Example
customDimension string One of the available dimension values set in the configuration phase. Will persist cross session. Set to empty string to reset. ninja

Read more about custom dimensions here.


debug & verify

Copy link to clipboard


Copy link to clipboard

The SDK is designed to be as silent as possible and use very few resources. You will therefore not get much information by default in your development console.

We have 2 different debug log types that can be enabled / disabled (at any time).

  • info log
  • verbose log

Info log

Short messages will be output when enabled explaining when some action is being performed by the SDK. Sometimes cropping text / values to make it more readable.

Enable info log when implementing the SDK – remember to turn it off in production!

Info/GameAnalytics: Add DESIGN event: {eventId:someEvent, value:0}
 Info/GameAnalytics: Add DESIGN event: {eventId:someOtherEvent, value:100}
 Info/GameAnalytics: Add ERROR event: {severity:info, message:This is some in}

Verbose Log

Console output when each event is added (all fields) in JSON string format. This is the data being submitted to the GA servers for each event.

Enable verbose log when troubleshooting events.


This can result in a lot of text. When troubleshooting/debugging events it is therefore recommended to enable/disable when performing the action that need inspection.

Troubleshooting example.

// enable verbose log
 // add event you need to troubnleshoot / inspect
 GameAnalytics.NewDesignEvent("Some:Event", 100);
 // disable verbose log 

Verify Implementation

Copy link to clipboard

Enable the Info Log to verify that events are being sent from your game project without any issues being reported.

Events submitted should register after a minor delay in our realtime dashboard in the GameAnalytics tool.

Read more about the realtime dashboard and our data processing.


how does it work?

Copy link to clipboard

Session Handling

Copy link to clipboard

Sessions are the concept of a user spending focused time in your game – from game launch to the user leaving the game.

Session start

  1. Generate new session.
  2. Add a session start event (a “user” event).
  3. Start the periodic activation of submitting queued events.
  4. Next event submit will fix potential missing session_end from earlier sessions.

Session end

  1. Stop the periodic activation of submitting queued events.
  2. Add a session_end event.
  3. Submit queued events.

If you are deploying testflight builds then please note that every launch of the game will generate a new user. This is due to how testflight is simulating certain device identifiers. A testflight game will register the same user as a “New User” each time the game is launched. Once it is deployed to the app store (or run locally on an actual device) it will track users (returning etc.) correctly.


Event queue

Copy link to clipboard

Whenever an event is added (and validated) it will be added to a local database queue.


Every 8 seconds the SDK will start a task for submitting queued events since last submit. This processing is done in a separate low-priority thread that will have minimum impact on performance. The payload is gzipped and will therefore only consume a small amount of bandwidth.


When a device is offline the events are still added to the queue. When the device is online it will submit.


Thread Handling

Copy link to clipboard

Almost every piece of this code is run using a dedicated low-priority serial thread queue to avoid UI lag or sudden performance spikes.

The queue will execute each task sequentially. If the SDK add several tasks to the queue then each will be executed in turn. A task could be adding an event or submitting all queued events.

Consider this example with 3 calls.

// Configure build version
// Initialize
GameAnalytics.Initialize("12341234123412341234123412341234", "1234123412341234123412341234123412341234");
// Add Design event

The configureBuild is required to be called before initialize is completely finished. The design event call is required after initialize is finished. The queuing will make sure that each task is completely finished before proceeding to the next one.


There is more!

Copy link to clipboard

There is much more to GameAnalytics and we suggest that you read our general documentation.

Please create a support ticket if you have any feedback like..

  • bugs
  • confusing features or UI
  • great ideas!

We hope you enjoy our service!

Contact support

Any queries about the platform are welcome.

Give article feedback

Let us know what you think about the articles.